agentleFS
Liberty91LTDLiberty91LTD/cti-skills/skills/cti-setup/SKILL.md

cti-setup

Skill35 starsChanged 45 days agoMITView on GitHub

Use when the user wants to configure API keys for the CTI skills pack, asks "how do I set up keys", "configure VirusTotal", "add my Shodan key", or runs /cti-setup. Walks through API key configuration inside Claude Code without needing to run a shell script. Also handles re-running setup, adding individual keys, and verifying that configured keys work.

  • Reads credentials

The file

Show its rules and text

We split this skill into the rules it gives an agent

15 rules. About 0 are common, 5 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    After install via /plugin marketplace add or npx (no shell setup ran)

    line 18
  2. Very specific:

    Check current state: Read .claude/settings.local.json.

    line 22
  3. Very specific:

    Receive the keys: When the user shares a key, treat it as sensitive — do not echo it back in plain text in your response (refer to it as …

    line 25
  4. Very specific:

    Write the merged file: Use the non-destructive merge below — preserve every other field in settings.local.json.

    line 26
  5. Distinctive:

    Offer to verify: Ask if they want you to dry-run each configured key against its CLI to confirm it's wired up.

    line 27
  6. Very specific:

    If scripts/setup.sh is not present (e.g.

    line 74
  7. Distinctive:

    After writing, confirm to the user:

    line 92
  8. Distinctive:

    If the user wants to verify, run:

    line 99
  9. Very specific:

    Never commit .claude/settings.local.json (already gitignored at repo root).

    line 119
  10. Distinctive:

    Never echo the full key value back to the user in chat — they shared it once.

    line 120
  11. Distinctive:

    Don't write keys to logs, screenshots, or other artefacts.

    line 121
  12. Very specific:

    If the user accidentally pastes a key into a public channel, advise them to rotate it on the provider's site and re-run /cti-setup with the …

    line 122
  13. Very specific:

    Does not call the threat-intel APIs (only --dry-run invocations of the local CLIs).

    line 126
  14. Very specific:

    Does not download MITRE ATT&CK data — for that, run ./scripts/download-mitre.sh (the /mitre-attack skill self-heals on first use).

    line 127
  15. Very specific:

    Does not configure permissions, hooks, or other Claude Code settings — only the env block of settings.local.json.

    line 128

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

cti-setup

In-chat configuration of API keys for the threat-intel integrations bundled with this pack. Use this when the user is in Claude Code and doesn't want to drop to a shell to run ./scripts/setup.sh.

When to invoke

  • User asks "how do I set up keys", "configure my API keys", "add a VirusTotal key", etc.
  • User runs /cti-setup
  • A lookup-* skill failed because a key is missing and you want to offer to add it
  • After install via /plugin marketplace add or npx (no shell setup ran)

What you do

  1. Check current state. Read .claude/settings.local.json. If it's missing or has no env block, the user has zero keys configured. If it has some, list which are present and which are missing.
  2. Tell the user the menu. Present the services in a table with: name, env variable, free-tier limit, signup URL. Make clear all are optional and that the pack degrades gracefully.
  3. Ask which to configure. Let the user provide one, several, or all. Don't force them through every prompt.
  4. Receive the keys. When the user shares a key, treat it as sensitive — do not echo it back in plain text in your response (refer to it as your VirusTotal key or the masked tail …<last 4 chars>).
  5. Write the merged file. Use the non-destructive merge below — preserve every other field in settings.local.json.
  6. Offer to verify. Ask if they want you to dry-run each configured key against its CLI to confirm it's wired up.
  7. Tell them what's next. "Try /ip-investigation 8.8.8.8" or similar concrete next command.

The services

ServiceEnv variableFree tierSignup
Liberty91 (first-party)LIBERTY91_API_KEY (optional LIBERTY91_API_URL)per-key rate limit + monthly credits on your planLiberty91 platform → user menu → API Access (Owner/Admin only; the secret is shown once)
VirusTotalVIRUSTOTAL_API_KEY4/min, 500/dayvirustotal.com → profile → API key
URLScan.ioURLSCAN_API_KEY100 scans/dayurlscan.io → user settings
ShodanSHODAN_API_KEY1 req/secaccount.shodan.io
AbuseIPDBABUSEIPDB_API_KEY1000 checks/dayabuseipdb.com → account → API
GreyNoiseGREYNOISE_API_KEY50 req/day (community)viz.greynoise.io → account
AlienVault OTXOTX_API_KEY10k req/hourotx.alienvault.com → settings
CensysCENSYS_PAT250 queries/monthaccounts.censys.io → settings → personal-access-tokens
MISPMISP_URL + MISP_API_KEYself-hosted / org-providedyour MISP instance → My Profile → Auth keys
OpenCTIOPENCTI_URL + OPENCTI_TOKENself-hosted / org-providedyour OpenCTI instance → profile → API access (token)
Ransomware.liveRANSOMWARE_LIVE3000 req/day (PRO)my.ransomware.live → free PRO key
ReversingLabs A1000REVERSINGLABS_USER + REVERSINGLABS_PASSWORD (optional REVERSINGLABS_HOST)undocumented; 429+Retry-Afterlicensed product — issued by your RL admin or RL account team
CrowdStrike Falcon IntelligenceCROWDSTRIKE_CLIENT_ID + CROWDSTRIKE_CLIENT_SECRET (optional CROWDSTRIKE_BASE_URL)per-tenant; 429+Retry-Afterlicensed product — Falcon console → Support and resources → API clients and keys (assign Intel read scopes)
Microsoft SentinelSENTINEL_TENANT_ID + SENTINEL_CLIENT_ID + SENTINEL_CLIENT_SECRET + SENTINEL_WORKSPACE_IDyour Azure tenancy (query API is free; 200 queries/30s)Azure portal — Entra ID app registration + Log Analytics Reader role; walkthrough in tools/integrations/sentinel.md

If the user has a Liberty91 account, configure LIBERTY91_API_KEY first — it is the pack's first-party source and /lookup-liberty91 runs before third-party lookups, so it saves other services' quota. Keys are l91_live_ (production) or l91_test_ (development); an empty scope list on the key grants all read scopes, which is the right default for enrichment. Set LIBERTY91_API_URL only to point at a non-production host.

A starter set of VirusTotal + OTX + URLScan + AbuseIPDB covers most IP/domain/URL/hash investigations. Shodan and GreyNoise add value for IP-focused work. Censys is optional (very tight rate limit). MISP requires both a base URL and an auth key — point it at your org's instance. OpenCTI likewise takes a base URL plus an API token and powers /lookup-opencti (two-way: query your knowledge base + push vetted intel back). Ransomware.live powers the lookup-ransomwarelive and ransomware-ecosystem skills (victim/group tracking). ReversingLabs is a licensed product — only configure if your organisation has a Spectra Analyze (A1000) account. CrowdStrike Falcon Intelligence is a licensed subscription — it powers /lookup-crowdstrike for IOC reputation AND threat-actor / TTP / report intelligence; configure if your org has a Falcon Intelligence licence with Intel API scopes. Microsoft Sentinel takes four values and powers /lookup-sentinel (hunt your own workspace: IOC exposure sweeps + ATT&CK TTP hunts, read-only). All four come from the Azure portal: create an Entra ID app registration (→ tenant id + client id), add a client secret (shown once), grant the app Log Analytics Reader on the Sentinel workspace, and copy the Workspace ID from the workspace Overview blade — the step-by-step is in tools/integrations/sentinel.md. No extra licence is needed beyond the workspace itself.

How to write the file

The file is .claude/settings.local.json. It is gitignored. Do not overwrite it — read, merge the env block, write back. Use the bundled setup script which handles this safely:

./scripts/setup.sh --non-interactive \
  --liberty91=USER_PROVIDED_KEY \
  --virustotal=USER_PROVIDED_KEY \
  --shodan=USER_PROVIDED_KEY \
  --misp-url=https://misp.example.org \
  --misp=USER_PROVIDED_KEY \
  --opencti-url=https://opencti.example.org \
  --opencti=USER_PROVIDED_TOKEN \
  --ransomwarelive=USER_PROVIDED_KEY \
  --reversinglabs-user=USER_PROVIDED_USERNAME \
  --reversinglabs-password=USER_PROVIDED_PASSWORD \
  --reversinglabs-host=https://a1000.reversinglabs.com

(Pass only the flags for keys the user actually shared. Available flags: --liberty91, --liberty91-url, --virustotal, --urlscan, --shodan, --abuseipdb, --greynoise, --otx, --censys, --misp-url, --misp, --opencti-url, --opencti, --ransomwarelive, --reversinglabs-user, --reversinglabs-password, --reversinglabs-host, --crowdstrike-client-id, --crowdstrike-client-secret, --crowdstrike-base-url, --sentinel-tenant-id, --sentinel-client-id, --sentinel-client-secret, --sentinel-workspace-id.)

If scripts/setup.sh is not present (e.g. plugin-only install), do the merge yourself with this Node one-liner. Replace KEY=VAL pairs with the user's input:

node -e "
  const fs = require('fs');
  const path = '.claude/settings.local.json';
  let cur = {};
  try { cur = JSON.parse(fs.readFileSync(path, 'utf8')); } catch(e) {}
  cur.env = cur.env || {};
  Object.assign(cur.env, {
    VIRUSTOTAL_API_KEY: 'USER_PROVIDED_KEY',
    SHODAN_API_KEY: 'USER_PROVIDED_KEY',
  });
  fs.mkdirSync('.claude', { recursive: true });
  fs.writeFileSync(path, JSON.stringify(cur, null, 2) + '\n');
"

After writing, confirm to the user:

  • which keys were added (by service name, not the key value)
  • which keys are still unconfigured
  • that the file is gitignored

Verifying keys

If the user wants to verify, run:

./scripts/setup.sh --verify

This dry-runs each lookup CLI and reports OK/fail per service without making a real API call. If setup.sh is unavailable, dry-run each CLI individually:

node tools/clis/virustotal.js ip 8.8.8.8 --dry-run

Exit code 0 = key present and CLI invocation OK. Exit code 2 = missing key.

Removing or rotating a key

To remove a key, edit .claude/settings.local.json and delete the entry from the env block (or set its value to ""). To rotate, just re-run setup with the new value — the merge overwrites that key only.

Security notes

  • Never commit .claude/settings.local.json (already gitignored at repo root).
  • Never echo the full key value back to the user in chat — they shared it once; mask thereafter.
  • Don't write keys to logs, screenshots, or other artefacts.
  • If the user accidentally pastes a key into a public channel, advise them to rotate it on the provider's site and re-run /cti-setup with the new value.

What this does NOT do

  • Does not call the threat-intel APIs (only --dry-run invocations of the local CLIs).
  • Does not download MITRE ATT&CK data — for that, run ./scripts/download-mitre.sh (the /mitre-attack skill self-heals on first use).
  • Does not configure permissions, hooks, or other Claude Code settings — only the env block of settings.local.json.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.