Back to list
semgrep

semgrep

by semgrep

A collection of skills for AI coding agents from Semgrep

7🍴 1📅 Jan 24, 2026

SKILL.md


name: semgrep description: Run Semgrep static analysis scans and create custom detection rules. Use when asked to scan code with Semgrep, find security vulnerabilities, write custom YAML rules, or detect specific bug patterns.

Semgrep Static Analysis

Fast, pattern-based static analysis for security scanning and custom rule creation.

When to Use Semgrep

Ideal scenarios:

  • Quick security scans (minutes, not hours)
  • Pattern-based bug and vulnerability detection
  • Enforcing coding standards and best practices
  • Finding known vulnerability patterns (OWASP, CWE)
  • Creating custom detection rules for your codebase
  • Data flow analysis with taint mode

Installation

# pip (recommended)
python3 -m pip install semgrep

# Homebrew
brew install semgrep

# Docker
docker run --rm -v "${PWD}:/src" semgrep/semgrep semgrep --config auto /src

Part 1: Running Scans

Quick Scan

semgrep --config auto .                    # Auto-detect rules

Using Rulesets

semgrep --config p/<RULESET> .             # Single ruleset
semgrep --config p/security-audit --config p/trailofbits .  # Multiple
RulesetDescription
p/defaultGeneral security and code quality
p/security-auditComprehensive security rules
p/owasp-top-tenOWASP Top 10 vulnerabilities
p/cwe-top-25CWE Top 25 vulnerabilities
p/trailofbitsTrail of Bits security rules
p/pythonPython-specific
p/javascriptJavaScript-specific
p/golangGo-specific

Output Formats

semgrep --config p/security-audit --sarif -o results.sarif .   # SARIF
semgrep --config p/security-audit --json -o results.json .     # JSON

Scan Specific Paths

semgrep --config p/python app.py           # Single file
semgrep --config p/javascript src/         # Directory
semgrep --config auto --include='**/test/**' .  # Include tests

Configuration

.semgrepignore

tests/fixtures/
**/testdata/
generated/
vendor/
node_modules/

Suppress False Positives

password = get_from_vault()  # nosemgrep: hardcoded-password
dangerous_but_safe()  # nosemgrep

Part 2: Creating Custom Rules

When to Create Custom Rules

  • Detecting project-specific vulnerability patterns
  • Enforcing internal coding standards
  • Building security checks for custom frameworks
  • Creating taint-mode rules for data flow analysis

Approach Selection

ApproachUse When
Taint modeData flows from untrusted source to dangerous sink (injection vulnerabilities)
Pattern matchingSyntactic patterns without data flow requirements (deprecated APIs, hardcoded values)

Prioritize taint mode for injection vulnerabilities. Pattern matching alone can't distinguish between eval(user_input) (vulnerable) and eval("safe_literal") (safe).

Quick Start: Pattern Matching

rules:
  - id: hardcoded-password
    languages: [python]
    message: "Hardcoded password detected: $PASSWORD"
    severity: ERROR
    pattern: password = "$PASSWORD"

Quick Start: Taint Mode

rules:
  - id: command-injection
    languages: [python]
    message: User input flows to command execution
    severity: ERROR
    mode: taint
    pattern-sources:
      - pattern: request.args.get(...)
      - pattern: request.form[...]
    pattern-sinks:
      - pattern: os.system(...)
      - pattern: subprocess.call($CMD, shell=True, ...)
    pattern-sanitizers:
      - pattern: shlex.quote(...)

Pattern Syntax Quick Reference

SyntaxDescriptionExample
...Match anythingfunc(...)
$VARCapture metavariable$FUNC($INPUT)
<... ...>Deep expression match<... user_input ...>
OperatorDescription
patternMatch exact pattern
patternsAll must match (AND)
pattern-eitherAny matches (OR)
pattern-notExclude matches
pattern-insideMatch only inside context
pattern-not-insideMatch only outside context
metavariable-regexRegex on captured value

Testing Rules

Test-first is mandatory. Create test files with annotations:

# test_rule.py
def test_vulnerable():
    user_input = request.args.get("id")
    # ruleid: my-rule-id
    cursor.execute("SELECT * FROM users WHERE id = " + user_input)

def test_safe():
    user_input = request.args.get("id")
    # ok: my-rule-id
    cursor.execute("SELECT * FROM users WHERE id = ?", (user_input,))

Run tests:

semgrep --test --config rule.yaml test-file

Command Reference

TaskCommand
Run testssemgrep --test --config rule.yaml test-file
Validate YAMLsemgrep --validate --config rule.yaml
Dump ASTsemgrep --dump-ast -l <lang> <file>
Debug taint flowsemgrep --dataflow-traces -f rule.yaml file

Rule Creation Workflow

  1. Analyze the problem - Understand the bug pattern, determine taint vs pattern approach
  2. Create test cases first - Write ruleid: and ok: annotations before the rule
  3. Analyze AST - Run semgrep --dump-ast to understand code structure
  4. Write the rule - Start simple, iterate
  5. Test until 100% pass - No "missed lines" or "incorrect lines"
  6. Optimize patterns - Remove redundancies only after tests pass

Output structure:

<rule-id>/
├── <rule-id>.yaml     # Semgrep rule
└── <rule-id>.<ext>    # Test file

Detailed References

Official Semgrep Documentation:

Local References:

Anti-Patterns to Avoid

Too broad:

# BAD: Matches any function call
pattern: $FUNC(...)

# GOOD: Specific dangerous function
pattern: eval(...)

Missing safe cases:

# BAD: Only tests vulnerable case
# ruleid: my-rule
dangerous(user_input)

# GOOD: Include safe cases
# ruleid: my-rule
dangerous(user_input)

# ok: my-rule
dangerous(sanitize(user_input))

Rationalizations to Reject

ShortcutWhy It's Wrong
"Semgrep found nothing, code is clean"Semgrep is pattern-based; can't track complex cross-function data flow
"The pattern looks complete"Untested rules have hidden false positives/negatives
"It matches the vulnerable case"Matching vulnerabilities is half the job; verify safe cases don't match
"Taint mode is overkill"For injection vulnerabilities, taint mode gives better precision
"One test case is enough"Include edge cases: different coding styles, sanitized inputs, safe alternatives

CI/CD Integration

GitHub Actions

name: Semgrep

on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: '0 0 1 * *'

jobs:
  semgrep:
    runs-on: ubuntu-latest
    container:
      image: returntocorp/semgrep

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Run Semgrep
        run: |
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            semgrep ci --baseline-commit ${{ github.event.pull_request.base.sha }}
          else
            semgrep ci
          fi
        env:
          SEMGREP_RULES: >-
            p/security-audit
            p/owasp-top-ten
            p/trailofbits

Resources

Rule Writing:

General:

Score

Total Score

55/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon