Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Creates custom Semgrep rules for detecting security vulnerabilities, bug patterns, and code patterns. Use when writing Semgrep rules or building custom static analysis detections.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 186% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 481% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 400% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 137% | 0% |
Create production-quality Semgrep rules with proper testing and validation.
Ideal scenarios:
Do NOT use this skill for:
static-analysis skill)When writing Semgrep rules, reject these common shortcuts:
semgrep --test --config <rule-id>.yaml <rule-id>.<ext> to verify. Untested rules have hidden false positives/negatives.Too broad - matches everything, useless for detection:
yaml# BAD: Matches any function call pattern: $FUNC(...) # GOOD: Specific dangerous function pattern: eval(...)
Missing safe cases in tests - leads to undetected false positives:
python# BAD: Only tests vulnerable case # ruleid: my-rule dangerous(user_input) # GOOD: Include safe cases to verify no false positives # ruleid: my-rule dangerous(user_input) # ok: my-rule dangerous(sanitize(user_input)) # ok: my-rule dangerous("hardcoded_safe_value")
Overly specific patterns - misses variations:
yaml# BAD: Only matches exact format pattern: os.system("rm " + $VAR) # GOOD: Matches all os.system calls with taint tracking mode: taint pattern-sources: - pattern: input(...) pattern-sinks: - pattern: os.system(...)
This workflow is strict - do not skip steps:
languages: generic)todook and todoruleid test annotations: todoruleid: <rule-id> and todook: <rule-id> annotations in tests files for future rule improvements are forbiddenThis skill guides creation of Semgrep rules that detect security vulnerabilities and code patterns. Rules are created iteratively: analyze the problem, write tests first, analyze AST structure, write the rule, iterate until all tests pass, optimize the rule.
Approach selection:
Why prioritize taint mode? Pattern matching finds syntax but misses context. A pattern eval($X) matches both eval(user_input) (vulnerable) and eval("safe_literal") (safe). Taint mode tracks data flow, so it only alerts when untrusted data actually reaches the sink—dramatically reducing false positives for injection vulnerabilities.
Iterating between approaches: It's okay to experiment. If you start with taint mode and it's not working well (e.g., taint doesn't propagate as expected, too many false positives/negatives), switch to pattern matching. Conversely, if pattern matching produces too many false positives on safe cases, try taint mode instead. The goal is a working rule—not rigid adherence to one approach.
Output structure - exactly 2 files in a directory named after the rule-id:
<rule-id>/
├── <rule-id>.yaml # Semgrep rule
└── <rule-id>.<ext> # Test file with ruleid/ok annotationsyamlrules: - id: insecure-eval languages: [python] severity: HIGH message: User input passed to eval() allows code execution mode: taint pattern-sources: - pattern: request.args.get(...) pattern-sinks: - pattern: eval(...)
Test file (insecure-eval.py):
python# ruleid: insecure-eval eval(request.args.get('code')) # ok: insecure-eval eval("print('safe')")
Run tests (from rule directory): semgrep --test --config <rule-id>.yaml <rule-id>.<ext>
Copy this checklist and track progress:
Semgrep Rule Progress:
- [ ] Step 1: Analyze the Problem
- [ ] Step 2: Write Tests First
- [ ] Step 3: Analyze AST structure
- [ ] Step 4: Write the rule
- [ ] Step 5: Iterate until all tests pass (semgrep --test)
- [ ] Step 6: Optimize the rule (remove redundancies, re-test)
- [ ] Step 7: Final RunREQUIRED: Before writing any rule, use WebFetch to read all of these 7 links with Semgrep documentation:
Other measured skills in the registry, with their headline benchmark lift.