From cb581bf93dd3ed49a59782cebb6ad829857adfe4 Mon Sep 17 00:00:00 2001 From: alex s <46074070+bearsyankees@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:26:08 -0500 Subject: [PATCH] Feat/str 1646 opengrep (#1625) * feat(sandbox): replace Semgrep with Opengrep and bundle offline rules * fix(sandbox): keep opengrep-rules LICENSE and drop proprietary-licensed rules * feat(sandbox): add Strix rule for GitHub-owned actions not pinned to a commit SHA * chore: bump sandbox image to 1.4.0 (opengrep) * fix(sandbox): resolve the gitleaks release tag without the GitHub API * fix(sandbox): install a pinned, sha256-verified trivy release --- containers/Dockerfile | 56 +++++++++++++-- ...owned-action-not-pinned-to-commit-sha.yaml | 37 ++++++++++ docs/advanced/configuration.mdx | 2 +- docs/tools/sandbox.mdx | 2 +- docs/tools/terminal.mdx | 2 +- docs/usage/scan-modes.mdx | 2 +- scripts/install.sh | 2 +- strix/agents/prompts/system_prompt.jinja | 10 +-- strix/config/settings.py | 2 +- strix/skills/README.md | 2 +- .../coordination/source_aware_whitebox.md | 8 +-- strix/skills/custom/source_aware_sast.md | 27 +++---- strix/skills/frameworks/django.md | 4 +- strix/skills/scan_modes/deep.md | 2 +- strix/skills/scan_modes/quick.md | 2 +- strix/skills/scan_modes/standard.md | 2 +- strix/skills/tooling/opengrep.md | 69 ++++++++++++++++++ strix/skills/tooling/semgrep.md | 72 ------------------- 18 files changed, 193 insertions(+), 110 deletions(-) create mode 100644 containers/opengrep-rules/github-owned-action-not-pinned-to-commit-sha.yaml create mode 100644 strix/skills/tooling/opengrep.md delete mode 100644 strix/skills/tooling/semgrep.md diff --git a/containers/Dockerfile b/containers/Dockerfile index 7d125ca83..a1ff49ef0 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -186,13 +186,27 @@ RUN set -eux; \ aarch64|arm64) GITLEAKS_ARCH="arm64" ;; \ *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; \ esac; \ - TAG="$(curl -fsSL https://api.github.com/repos/gitleaks/gitleaks/releases/latest | jq -r .tag_name)"; \ + TAG="$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/gitleaks/gitleaks/releases/latest | sed 's#.*/##')"; \ curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/${TAG}/gitleaks_${TAG#v}_linux_${GITLEAKS_ARCH}.tar.gz" -o /tmp/gitleaks.tgz; \ tar -xzf /tmp/gitleaks.tgz -C /tmp; \ install -m 0755 /tmp/gitleaks /usr/local/bin/gitleaks; \ rm -f /tmp/gitleaks /tmp/gitleaks.tgz -RUN curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin +ARG TRIVY_VERSION=0.76.1 +ARG TRIVY_SHA256_X86=c7cbe3137fb8a48a17574bede3dd6beb16742d1e9772929940fc90082c39d9c0 +ARG TRIVY_SHA256_AARCH64=e174dff2a6dba5e3ae41f8d0537a6324405bd08132497340304c6b20e0f16a1f +RUN set -eux; \ + case "$(uname -m)" in \ + x86_64) TRIVY_ARCH="64bit"; TRIVY_SHA256="${TRIVY_SHA256_X86}" ;; \ + aarch64|arm64) TRIVY_ARCH="ARM64"; TRIVY_SHA256="${TRIVY_SHA256_AARCH64}" ;; \ + *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; \ + esac; \ + curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-${TRIVY_ARCH}.tar.gz" -o /tmp/trivy.tgz; \ + echo "${TRIVY_SHA256} /tmp/trivy.tgz" | sha256sum -c -; \ + tar -xzf /tmp/trivy.tgz -C /tmp trivy; \ + install -m 0755 /tmp/trivy /usr/local/bin/trivy; \ + rm -f /tmp/trivy /tmp/trivy.tgz; \ + trivy --version RUN apt-get install -y wapiti @@ -212,10 +226,44 @@ RUN set -eux; \ test "$(dpkg-query -W -f='${Version}' libbrotli1)" = "${BROTLI_DEB_VERSION}"; \ node -e 'const z=require("zlib");z.brotliDecompressSync(z.brotliCompressSync(Buffer.from("ok")))' +ARG OPENGREP_VERSION=1.31.0 +ARG OPENGREP_SHA256_X86=dbbe3c2058dbe600c449a8ba22ea79a1643a6660658400090d0323a8d0d31147 +ARG OPENGREP_SHA256_AARCH64=2b713a29a00237f85408b83002fc111db5b94c7fa8d263f0a93184a960655d9d +RUN set -eux; \ + case "$(uname -m)" in \ + x86_64) OPENGREP_ARCH="x86"; OPENGREP_SHA256="${OPENGREP_SHA256_X86}" ;; \ + aarch64|arm64) OPENGREP_ARCH="aarch64"; OPENGREP_SHA256="${OPENGREP_SHA256_AARCH64}" ;; \ + *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; \ + esac; \ + curl -fsSL "https://github.com/opengrep/opengrep/releases/download/v${OPENGREP_VERSION}/opengrep_manylinux_${OPENGREP_ARCH}" -o /tmp/opengrep; \ + echo "${OPENGREP_SHA256} /tmp/opengrep" | sha256sum -c -; \ + install -m 0755 /tmp/opengrep /usr/local/bin/opengrep; \ + rm -f /tmp/opengrep; \ + opengrep --version + +# Opengrep ships no rule registry of its own; bake the community ruleset so +# scans run offline. Keep only rule YAML and LICENSE; drop tests, fixtures, +# tooling, and rules marked with a proprietary license. +ARG OPENGREP_RULES_REF=f1d2b562b414783763fd02a6ed2736eaed622efa +RUN set -eux; \ + mkdir -p /opt/opengrep-rules; \ + curl -fsSL "https://codeload.github.com/opengrep/opengrep-rules/tar.gz/${OPENGREP_RULES_REF}" \ + | tar -xz --strip-components=1 -C /opt/opengrep-rules; \ + cd /opt/opengrep-rules; \ + rm -rf .github scripts stats; \ + find . -maxdepth 1 -type f ! -name LICENSE -delete; \ + find . -mindepth 2 -type f \( ! \( -name '*.yaml' -o -name '*.yml' \) -o -name '*.test.yaml' -o -name '*.test.yml' -o -name '.*' \) -delete; \ + grep -rlZ 'license: proprietary' . | xargs -0 -r rm -f; \ + find . -type d -empty -delete; \ + chmod -R a+rX /opt/opengrep-rules + +# Strix-authored rules that close gaps in the community ruleset. +COPY containers/opengrep-rules/ /opt/opengrep-rules/strix/ +RUN chmod -R a+rX /opt/opengrep-rules/strix + USER pentester -RUN pipx install semgrep && \ - pipx install bandit +RUN pipx install bandit RUN npm install -g jshint diff --git a/containers/opengrep-rules/github-owned-action-not-pinned-to-commit-sha.yaml b/containers/opengrep-rules/github-owned-action-not-pinned-to-commit-sha.yaml new file mode 100644 index 000000000..0640684bf --- /dev/null +++ b/containers/opengrep-rules/github-owned-action-not-pinned-to-commit-sha.yaml @@ -0,0 +1,37 @@ +rules: + - id: github-owned-action-not-pinned-to-commit-sha + patterns: + - pattern-inside: "{steps: ...}" + - pattern: | + uses: "$USES" + - metavariable-regex: + metavariable: $USES + regex: '^(actions|github)/' + - metavariable-pattern: + metavariable: $USES + language: generic + patterns: + - pattern-not-regex: "@[0-9a-f]{40}$" + message: >- + GitHub-owned action `$USES` is referenced by a mutable tag or branch + instead of a full-length commit SHA. Tags can be moved, so a compromised + or force-pushed release changes what this workflow runs. Pin to the + commit SHA of the release you reviewed and let a bot keep it current. + languages: + - yaml + severity: WARNING + metadata: + cwe: + - "CWE-1357: Reliance on Insufficiently Trustworthy Component" + - "CWE-353: Missing Support for Integrity Check" + owasp: A06:2021 - Vulnerable and Outdated Components + references: + - https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-third-party-actions + category: security + technology: + - github-actions + subcategory: + - vuln + likelihood: LOW + impact: LOW + confidence: HIGH diff --git a/docs/advanced/configuration.mdx b/docs/advanced/configuration.mdx index 247c0994e..29be4c871 100644 --- a/docs/advanced/configuration.mdx +++ b/docs/advanced/configuration.mdx @@ -186,7 +186,7 @@ When remote vars are set, Strix dual-writes telemetry to both local JSONL and th ## Docker Configuration - + Docker image to use for the sandbox container. diff --git a/docs/tools/sandbox.mdx b/docs/tools/sandbox.mdx index 386452f7f..aebb07cc1 100644 --- a/docs/tools/sandbox.mdx +++ b/docs/tools/sandbox.mdx @@ -49,7 +49,7 @@ Strix runs inside a Kali Linux-based Docker container with a comprehensive set o | Tool | Description | | ------------------------------------------------------- | --------------------------------------------- | -| [Semgrep](https://github.com/semgrep/semgrep) | Fast SAST and custom rule matching | +| [Opengrep](https://github.com/opengrep/opengrep) | Fast SAST and custom rule matching | | [ast-grep](https://ast-grep.github.io) | Structural AST/CST-aware code search (`sg`) | | [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) | Syntax tree parsing and symbol extraction (Java/JS/TS/Python/Go/Bash/JSON/YAML grammars pre-configured) | | [Bandit](https://bandit.readthedocs.io) | Python security linter | diff --git a/docs/tools/terminal.mdx b/docs/tools/terminal.mdx index 5f7cb8410..47c7c76f5 100644 --- a/docs/tools/terminal.mdx +++ b/docs/tools/terminal.mdx @@ -33,7 +33,7 @@ sqlmap -u "https://example.com/page?id=1" ```bash # Fast SAST triage -semgrep --config auto ./src +opengrep scan --config /opt/opengrep-rules ./src # Structural AST search sg scan ./src diff --git a/docs/usage/scan-modes.mdx b/docs/usage/scan-modes.mdx index 9f9589103..48d044792 100644 --- a/docs/usage/scan-modes.mdx +++ b/docs/usage/scan-modes.mdx @@ -46,7 +46,7 @@ Thorough penetration testing. Best for: **Duration**: 1-4 hours depending on target complexity -**White-box behavior**: Runs broad source-aware triage (`semgrep`, AST structural search, secrets, supply-chain checks) and then systematically validates top candidates dynamically. +**White-box behavior**: Runs broad source-aware triage (`opengrep`, AST structural search, secrets, supply-chain checks) and then systematically validates top candidates dynamically. Deep mode is the default. It explores edge cases, chained vulnerabilities, and complex attack paths. diff --git a/scripts/install.sh b/scripts/install.sh index 876f11db2..78f8c97d8 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -4,7 +4,7 @@ set -euo pipefail APP=strix REPO="usestrix/strix" -STRIX_IMAGE="ghcr.io/usestrix/strix-sandbox:1.3.1" +STRIX_IMAGE="ghcr.io/usestrix/strix-sandbox:1.4.0" MUTED='\033[0;2m' RED='\033[0;31m' diff --git a/strix/agents/prompts/system_prompt.jinja b/strix/agents/prompts/system_prompt.jinja index fd09d0774..6c6a0ab95 100644 --- a/strix/agents/prompts/system_prompt.jinja +++ b/strix/agents/prompts/system_prompt.jinja @@ -115,11 +115,11 @@ BLACK-BOX TESTING (domain/subdomain only): WHITE-BOX TESTING (code provided): - MUST perform BOTH static AND dynamic analysis -- Static: Use source-aware triage first to map risk quickly (`semgrep`, `ast-grep`, Tree-sitter tooling, `gitleaks`, `trufflehog`, `trivy fs`). Then review code for vulnerabilities +- Static: Use source-aware triage first to map risk quickly (`opengrep`, `ast-grep`, Tree-sitter tooling, `gitleaks`, `trufflehog`, `trivy fs`). Then review code for vulnerabilities - Static coverage floor: execute at least one structural AST mapping pass (`sg` and/or Tree-sitter) per repository and keep artifact output -- Static coverage target per repository: run one `semgrep` pass, one secrets pass (`gitleaks` and/or `trufflehog`), one `trivy fs` pass, and one AST-structural pass (`sg` and/or Tree-sitter) +- Static coverage target per repository: run one `opengrep` pass, one secrets pass (`gitleaks` and/or `trufflehog`), one `trivy fs` pass, and one AST-structural pass (`sg` and/or Tree-sitter) - Keep AST artifacts bounded and high-signal: scope to relevant paths/hypotheses, avoid whole-repo generic function dumps -- AST target selection rule: build `sg-targets.txt` from `semgrep.json` scope first (`paths.scanned`, fallback to unique `results[].path`), then run `xargs ... sg run` against that file list. Only use path-heuristic fallback if semgrep scope is unavailable. +- AST target selection rule: build `sg-targets.txt` from `opengrep.json` scope first (`paths.scanned`, fallback to unique `results[].path`), then run `xargs ... sg run` against that file list. Only use path-heuristic fallback if opengrep scope is unavailable. - Dynamic: Run the application and test live to validate exploitability - NEVER rely solely on static code analysis when dynamic validation is possible - Begin with fast source triage and dynamic run preparation in parallel; use static findings to prioritize live testing. @@ -188,7 +188,7 @@ EFFICIENCY TACTICS: - For Caido proxy automation inside Python, explicitly import from `caido_api`: `from caido_api import list_requests, view_request, repeat_request, list_sitemap, view_sitemap_entry, scope_rules` -- Prefer established fuzzers/scanners where applicable: ffuf, sqlmap, nuclei, wapiti, arjun, httpx, katana, semgrep, bandit, trufflehog, nmap. Use scripts mainly to coordinate or validate around them, not to replace them without reason +- Prefer established fuzzers/scanners where applicable: ffuf, sqlmap, nuclei, wapiti, arjun, httpx, katana, opengrep, bandit, trufflehog, nmap. Use scripts mainly to coordinate or validate around them, not to replace them without reason - For trial-heavy vectors (SQLi, XSS, XXE, SSRF, RCE, auth/JWT, deserialization), DO NOT iterate payloads manually in the browser. Always spray payloads via Python scripts through `exec_command` or terminal tools. - When using established fuzzers/scanners, use the proxy for inspection where helpful - Generate/adapt large payload corpora: combine encodings (URL, unicode, base64), comment styles, wrappers, time-based/differential probes. Expand with wordlists/templates @@ -458,7 +458,7 @@ JAVASCRIPT ANALYSIS: - js-beautify - JS beautifier/deobfuscator CODE ANALYSIS: -- semgrep - Static analysis/SAST +- opengrep - Static analysis/SAST (bundled rules in /opt/opengrep-rules) - ast-grep (sg) - Structural AST/CST-aware code search - tree-sitter - Syntax-aware parsing and symbol extraction support - bandit - Python security linter diff --git a/strix/config/settings.py b/strix/config/settings.py index 9b216aa99..4db49d5d8 100644 --- a/strix/config/settings.py +++ b/strix/config/settings.py @@ -164,7 +164,7 @@ class RuntimeSettings(BaseSettings): model_config = _BASE_CONFIG image: str = Field( - default="ghcr.io/usestrix/strix-sandbox:1.3.1", + default="ghcr.io/usestrix/strix-sandbox:1.4.0", alias="STRIX_IMAGE", ) backend: str = Field(default="docker", alias="STRIX_RUNTIME_BACKEND") diff --git a/strix/skills/README.md b/strix/skills/README.md index 87a48ddfa..d87d09412 100644 --- a/strix/skills/README.md +++ b/strix/skills/README.md @@ -40,7 +40,7 @@ The skills are dynamically injected into the agent's system prompt, allowing it Notable source-aware skills: - `source_aware_whitebox` (coordination): white-box orchestration playbook -- `source_aware_sast` (custom): semgrep/AST/secrets/supply-chain static triage workflow +- `source_aware_sast` (custom): opengrep/AST/secrets/supply-chain static triage workflow - `dependency_cve_scanning` (custom): trivy-based SCA workflow for reporting known dependency CVEs via `create_dependency_report` - `npx_confusion` (custom): npx/npm exec/bunx fallback and adjacent package-runner identity confusion, with runner-specific registry and reporting gates - `semantic_confusion` (vulnerabilities): cross-boundary parser, normalization, and representation mismatch analysis diff --git a/strix/skills/coordination/source_aware_whitebox.md b/strix/skills/coordination/source_aware_whitebox.md index d8849e638..24d734a47 100644 --- a/strix/skills/coordination/source_aware_whitebox.md +++ b/strix/skills/coordination/source_aware_whitebox.md @@ -14,22 +14,22 @@ Increase white-box coverage by combining source-aware triage with dynamic valida ## Recommended Workflow 1. Build a quick source map before deep exploitation, including at least one AST-structural pass (`sg` or `tree-sitter`) scoped to relevant paths. - - For `sg` baseline, derive `sg-targets.txt` from `semgrep.json` scope first (`paths.scanned`, fallback to unique `results[].path`) and run `xargs ... sg run` on that list. - - Only fall back to path heuristics when semgrep scope is unavailable. + - For `sg` baseline, derive `sg-targets.txt` from `opengrep.json` scope first (`paths.scanned`, fallback to unique `results[].path`) and run `xargs ... sg run` on that list. + - Only fall back to path heuristics when opengrep scope is unavailable. 2. Run first-pass static triage to rank high-risk paths. 3. Use triage outputs to prioritize dynamic PoC validation. 4. Keep findings evidence-driven: no report without validation. ## Source-Aware Triage Stack -- `semgrep`: fast security-first triage and custom pattern scans +- `opengrep`: fast security-first triage and custom pattern scans - `ast-grep` (`sg`): structural pattern hunting and targeted repo mapping - `tree-sitter`: syntax-aware parsing support for symbol and route extraction - `gitleaks` + `trufflehog`: complementary secret detection (working tree and history coverage) - `trivy fs`: dependency, misconfiguration, license, and secret checks Coverage target per repository: -- one `semgrep` pass +- one `opengrep` pass - one AST structural pass (`sg` and/or `tree-sitter`) - one secrets pass (`gitleaks` and/or `trufflehog`) - one `trivy fs` pass diff --git a/strix/skills/custom/source_aware_sast.md b/strix/skills/custom/source_aware_sast.md index fee2fd921..0c44267d8 100644 --- a/strix/skills/custom/source_aware_sast.md +++ b/strix/skills/custom/source_aware_sast.md @@ -1,6 +1,6 @@ --- name: source-aware-sast -description: Practical source-aware SAST and AST playbook for semgrep, ast-grep, gitleaks, and trivy fs +description: Practical source-aware SAST and AST playbook for opengrep, ast-grep, gitleaks, and trivy fs --- # Source-Aware SAST Playbook @@ -23,19 +23,19 @@ Run this baseline once per repository before deep narrowing: ART=/workspace/.source-aware mkdir -p "$ART" -semgrep scan --config p/default --config p/golang --config p/secrets \ - --metrics=off --json --output "$ART/semgrep.json" . -# Build deterministic AST targets from semgrep scope (no hardcoded path guessing) +opengrep scan --config /opt/opengrep-rules --taint-intrafile \ + --json --output "$ART/opengrep.json" . +# Build deterministic AST targets from opengrep scope (no hardcoded path guessing) python3 - <<'PY' import json from pathlib import Path art = Path("/workspace/.source-aware") -semgrep_json = art / "semgrep.json" +opengrep_json = art / "opengrep.json" targets_file = art / "sg-targets.txt" try: - data = json.loads(semgrep_json.read_text(encoding="utf-8")) + data = json.loads(opengrep_json.read_text(encoding="utf-8")) except Exception: targets_file.write_text("", encoding="utf-8") raise @@ -63,17 +63,18 @@ trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \ --format json --output "$ART/trivy-fs.json" . || true ``` -## Semgrep First Pass +## Opengrep First Pass -Use Semgrep as the default static triage pass: +Use Opengrep as the default static triage pass. Rules are bundled offline in `/opt/opengrep-rules` (one directory per language, plus `generic/secrets`): ```bash -# Preferred deterministic profile set (works with --metrics=off) -semgrep scan --config p/default --config p/golang --config p/secrets \ - --metrics=off --json --output /workspace/.source-aware/semgrep.json . +# Full bundled ruleset +opengrep scan --config /opt/opengrep-rules --taint-intrafile \ + --json --output /workspace/.source-aware/opengrep.json . -# If you choose auto config, do not combine it with --metrics=off -semgrep scan --config auto --json --output /workspace/.source-aware/semgrep-auto.json . +# Narrow to the target stack when the full set is slow or noisy +opengrep scan --config /opt/opengrep-rules/python --config /opt/opengrep-rules/generic/secrets \ + --taint-intrafile --json --output /workspace/.source-aware/opengrep-python.json . ``` If diff scope is active, restrict to changed files first, then expand only when needed. diff --git a/strix/skills/frameworks/django.md b/strix/skills/frameworks/django.md index 143e6e905..4fee70121 100644 --- a/strix/skills/frameworks/django.md +++ b/strix/skills/frameworks/django.md @@ -205,10 +205,10 @@ Jinja2 backend without autoescape: `{{7*7}}`, RCE gadgets if sandbox misconfigur ## Tooling -Static analysis is the fastest way to reach the sinks above in white-box scope. The sandbox ships `python`/`pipx`, `semgrep`, `bandit`, `ast-grep`, and `ripgrep`. +Static analysis is the fastest way to reach the sinks above in white-box scope. The sandbox ships `python`/`pipx`, `opengrep`, `bandit`, `ast-grep`, and `ripgrep`. - **bandit** (preinstalled) — Python security linter; flags `mark_safe`, `extra()`, `RawSQL`, `subprocess`, weak crypto, hardcoded secrets: `bandit -r . -ll` -- **semgrep** (preinstalled) with the Django ruleset — higher-signal than bandit for framework-specific bugs (`.extra()`, `RawSQL`, `|safe`, `csrf_exempt`, `ALLOWED_HOSTS=['*']`): `semgrep --config p/django .` +- **opengrep** (preinstalled) with the bundled Django rules — higher-signal than bandit for framework-specific bugs (`.extra()`, `RawSQL`, `|safe`, `csrf_exempt`, `ALLOWED_HOSTS=['*']`): `opengrep scan --config /opt/opengrep-rules/python/django .` - **pip-audit** (PyPA) — dependency CVE scanner for known-vuln Django/DRF/simplejwt versions: `pipx install pip-audit && pip-audit -r requirements.txt` - **ast-grep** (preinstalled) — quick structural grep for risky calls without a full SAST run: `ast-grep run -p 'mark_safe($X)' -l python` diff --git a/strix/skills/scan_modes/deep.md b/strix/skills/scan_modes/deep.md index af2b85dd0..61fd0473b 100644 --- a/strix/skills/scan_modes/deep.md +++ b/strix/skills/scan_modes/deep.md @@ -15,7 +15,7 @@ Thorough understanding before exploitation. Test every parameter, every endpoint **Whitebox (source available)** - Map every file, module, and code path in the repository -- Start with broad source-aware triage (`semgrep`, `ast-grep`, `gitleaks`, `trufflehog`, `trivy fs`) and use outputs to drive deep review +- Start with broad source-aware triage (`opengrep`, `ast-grep`, `gitleaks`, `trufflehog`, `trivy fs`) and use outputs to drive deep review - Execute at least one structural AST pass (`sg` and/or Tree-sitter) per repository and store artifacts for reuse - Keep AST artifacts bounded and query-driven (target relevant paths/sinks first; avoid whole-repo generic function dumps) - Use syntax-aware parsing (Tree-sitter tooling) to improve symbol, route, and sink extraction quality diff --git a/strix/skills/scan_modes/quick.md b/strix/skills/scan_modes/quick.md index a8824786e..93be9b8e5 100644 --- a/strix/skills/scan_modes/quick.md +++ b/strix/skills/scan_modes/quick.md @@ -15,7 +15,7 @@ Optimize for fast feedback on critical security issues. Skip exhaustive enumerat **Whitebox (source available)** - Focus on recent changes: git diffs, new commits, modified files—these are most likely to contain fresh bugs -- Run a fast static triage on changed files first (`semgrep`, then targeted `sg` queries) +- Run a fast static triage on changed files first (`opengrep`, then targeted `sg` queries) - Run at least one lightweight AST pass (`sg` or Tree-sitter) so structural mapping is not skipped - Keep AST commands tightly scoped to changed or high-risk paths; avoid broad repository-wide pattern dumps - Run quick secret and dependency checks (`gitleaks`, `trufflehog`, `trivy fs`) scoped to changed areas when possible diff --git a/strix/skills/scan_modes/standard.md b/strix/skills/scan_modes/standard.md index b7a37395c..b44feb514 100644 --- a/strix/skills/scan_modes/standard.md +++ b/strix/skills/scan_modes/standard.md @@ -15,7 +15,7 @@ Systematic testing across the full attack surface. Understand the application be **Whitebox (source available)** - Map codebase structure: modules, entry points, routing -- Run `semgrep` first-pass triage to prioritize risky flows before deep manual review +- Run `opengrep` first-pass triage to prioritize risky flows before deep manual review - Run at least one AST-structural mapping pass (`sg` and/or Tree-sitter), then use outputs for route, sink, and trust-boundary mapping - Keep AST output bounded to relevant paths and hypotheses; avoid whole-repo generic function dumps - Identify architecture pattern (MVC, microservices, monolith) diff --git a/strix/skills/tooling/opengrep.md b/strix/skills/tooling/opengrep.md new file mode 100644 index 000000000..ae4a416b9 --- /dev/null +++ b/strix/skills/tooling/opengrep.md @@ -0,0 +1,69 @@ +--- +name: opengrep +description: Exact Opengrep CLI structure, bundled offline rules, scoped rule selection, taint mode, and automation-safe output patterns. +--- + +# Opengrep CLI Playbook + +Official docs: +- https://github.com/opengrep/opengrep +- https://github.com/opengrep/opengrep-rules + +Canonical syntax: +`opengrep scan [flags] [targets]` + +Bundled rules: +- `/opt/opengrep-rules` holds the full ruleset, one directory per language (`python`, `javascript`, `typescript`, `go`, `java`, `php`, `ruby`, …) plus `generic/secrets`, `dockerfile`, `terraform`, `yaml`, and `strix` (Strix-authored rules, e.g. GitHub-owned actions not pinned to a commit SHA) +- Framework rules sit under the language (`python/django`, `python/flask`, `javascript/express`, …) + +High-signal flags: +- `--config ` rule file or directory; repeat for several +- `--taint-intrafile` intra-file inter-procedural taint (follows data across functions in one file) +- `--json` / `--sarif` output format +- `--output ` write findings to file +- `--severity ` filter by severity (`INFO`, `WARNING`, `ERROR`) +- `--error` return non-zero exit when findings exist +- `--quiet` suppress progress noise +- `--jobs ` parallel workers +- `--timeout ` per-rule, per-file timeout +- `--exclude ` / `--include ` path filters +- `--exclude-rule ` suppress specific rule +- `--baseline-commit ` only report findings introduced after baseline + +Agent-safe baseline for automation: +`opengrep scan --config /opt/opengrep-rules --taint-intrafile --json --output opengrep.json --quiet --jobs 4 --timeout 20 /workspace` + +Common patterns: +- Full bundled scan: + `opengrep scan --config /opt/opengrep-rules --json --output opengrep.json --quiet /workspace` +- High-severity focused pass: + `opengrep scan --config /opt/opengrep-rules --severity ERROR --json --output opengrep_high.json --quiet /workspace` +- SARIF output: + `opengrep scan --config /opt/opengrep-rules --sarif --output opengrep.sarif --quiet /workspace` +- Language- or framework-specific rules: + `opengrep scan --config /opt/opengrep-rules/python --config /opt/opengrep-rules/generic/secrets --json --output opengrep_python.json --quiet /workspace` +- Scoped directory scan: + `opengrep scan --config /opt/opengrep-rules --json --output opengrep_api.json --quiet /workspace/services/api` +- Custom rule: + `opengrep scan --config ./rules/my-rule.yaml --json --output opengrep_custom.json --quiet /workspace` + +Critical correctness rules: +- Always provide an explicit `--config` from `/opt/opengrep-rules` or a local rule file. Registry shorthands (`p/...`, `auto`) fetch rules from the network; do not use them. +- Opengrep has no telemetry; there is no `--metrics` flag, and passing one fails the scan. +- Prefer `--json --output ` or `--sarif --output ` for machine-readable downstream processing. JSON keeps `paths.scanned` and `results[].path`. +- Keep the target path explicit; use an absolute or clearly scoped workspace path instead of `.` when possible. + +Usage rules: +- Start with the full `/opt/opengrep-rules` set unless the task clearly calls for a narrower language or framework directory. +- Add `--taint-intrafile` for injection-class hunting (SQLi, command injection, SSRF, path traversal) in supported languages. +- Use `--quiet` in automation to reduce noisy logs. +- Use `--jobs` and `--timeout` explicitly for reproducible runtime behavior. +- `PartialParsing` errors on templates are normal; they do not invalidate the run. + +Failure recovery: +- If scans are too slow, narrow the target path and the rule directories before changing engine settings. +- If scans time out, increase `--timeout` modestly or lower `--jobs`. +- If output is too broad, scope `--config`, add `--severity`, or exclude known irrelevant paths. + +If uncertain, query web_search with: +`site:github.com/opengrep/opengrep ` diff --git a/strix/skills/tooling/semgrep.md b/strix/skills/tooling/semgrep.md deleted file mode 100644 index 55cfe8d92..000000000 --- a/strix/skills/tooling/semgrep.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -name: semgrep -description: Exact Semgrep CLI structure, metrics-off scanning, scoped ruleset selection, and automation-safe output patterns. ---- - -# Semgrep CLI Playbook - -Official docs: -- https://semgrep.dev/docs/cli-reference -- https://semgrep.dev/docs/getting-started/cli -- https://semgrep.dev/docs/semgrep-code/semgrep-pro-engine-intro - -Canonical syntax: -`semgrep scan [flags]` - -High-signal flags: -- `--config ` ruleset, registry pack, local rule file, or directory -- `--metrics=off` disable telemetry and metrics reporting -- `--json` JSON output -- `--sarif` SARIF output -- `--output ` write findings to file -- `--severity ` filter by severity -- `--error` return non-zero exit when findings exist -- `--quiet` suppress progress noise -- `--jobs ` parallel workers -- `--timeout ` per-file timeout -- `--exclude ` exclude path pattern -- `--include ` include path pattern -- `--exclude-rule ` suppress specific rule -- `--baseline-commit ` only report findings introduced after baseline -- `--pro` enable Pro engine if available -- `--oss-only` force OSS engine only - -Agent-safe baseline for automation: -`semgrep scan --config p/default --metrics=off --json --output semgrep.json --quiet --jobs 4 --timeout 20 /workspace` - -Common patterns: -- Default security scan: - `semgrep scan --config p/default --metrics=off --json --output semgrep.json --quiet /workspace` -- High-severity focused pass: - `semgrep scan --config p/default --severity ERROR --metrics=off --json --output semgrep_high.json --quiet /workspace` -- OWASP-oriented scan: - `semgrep scan --config p/owasp-top-ten --metrics=off --sarif --output semgrep.sarif --quiet /workspace` -- Language- or framework-specific rules: - `semgrep scan --config p/python --config p/secrets --metrics=off --json --output semgrep_python.json --quiet /workspace` -- Scoped directory scan: - `semgrep scan --config p/default --metrics=off --json --output semgrep_api.json --quiet /workspace/services/api` -- Pro engine check or run: - `semgrep scan --config p/default --pro --metrics=off --json --output semgrep_pro.json --quiet /workspace` - -Critical correctness rules: -- Always include `--metrics=off`; Semgrep sends telemetry by default. -- Always provide an explicit `--config`; do not rely on vague or implied defaults. -- Prefer `--json --output ` or `--sarif --output ` for machine-readable downstream processing. -- Keep the target path explicit; use an absolute or clearly scoped workspace path instead of `.` when possible. -- If Pro availability matters, check it explicitly with a bounded command before assuming cross-file analysis exists. - -Usage rules: -- Start with `p/default` unless the task clearly calls for a narrower pack. -- Add focused packs such as `p/secrets`, `p/python`, or `p/javascript` only when they match the target stack. -- Use `--quiet` in automation to reduce noisy logs. -- Use `--jobs` and `--timeout` explicitly for reproducible runtime behavior. -- Do not use `-h`/`--help` for routine operation unless absolutely necessary. - -Failure recovery: -- If scans are too slow, narrow the target path and reduce the active rulesets before changing engine settings. -- If scans time out, increase `--timeout` modestly or lower `--jobs`. -- If output is too broad, scope `--config`, add `--severity`, or exclude known irrelevant paths. -- If Pro mode fails, rerun with `--oss-only` or without `--pro` and note the loss of cross-file coverage. - -If uncertain, query web_search with: -`site:semgrep.dev semgrep cli`