mrkeyoor.com_
Wed 23 Sept 00:34 UTC
PyPISecurityupdated 22 Sept 2026

semgrep review

Semgrep 1.174.0 is a static-analysis CLI that matches parsed program structure with YAML rules written in code-like patterns. The local Community Edition searches more than 30 languages, supports dataflow within its documented analysis boundary, and runs from an editor, pre-commit, or CI. Semgrep's hosted products add proprietary rules, cross-file and cross-function analysis, dependency reachability, secrets work, and finding triage. This release adds changed dependency-source reporting to diff scans and avoids dependency resolution for ecosystems outside the rules selected during a partial scan.

Verdict

Semgrep 1.174.0 installed in 1.8 seconds but occupied 316 MB across 66 packages in our sandbox, with 0 audit findings. Install it for syntax-aware rules that ordinary linters cannot express; do not treat the Community Edition result as cross-file AppSec coverage.

We installed it

Lab card: what happened when we installed semgrepScreenshot of semgrep documentation
Install✓ · 1.8s66 packages on disk · 316 MB
Importimport semdep in 0.02s · compiled extensions · py.typed · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does semgrep install cleanly?

Yes. In a fresh container with an empty cache, pip install semgrep finished in 2 seconds, leaving 66 packages and 316 MB on disk. pip-audit reported no known vulnerabilities.

What does semgrep need to run?

Python >=3.10, and a platform wheel with compiled extensions. In our run import semdep succeeded in 0.02s, and the package ships py.typed for type checkers.

semgrep or bandit: which should you use?

bandit: Choose it for a maintained set of Python security checks without a general structural rule engine. Semgrep 1.174.0 installed in 1.8 seconds but occupied 316 MB across 66 packages in our sandbox, with 0 audit findings.

When should you not use semgrep?

You expect the open-source engine to prove cross-file security properties. The README warns that Community Edition can miss findings beyond one function or file.

API stability4/5Rule building blocks such as `id`, `languages`, `message`, `severity`, `pattern`, `patterns`, `pattern-not`, metavariables, and `fix` are established, and `semgrep scan` remains the local command. The project ships frequent 1.x releases that adjust languages, targeting, flags, and outputs without a major-version wait. Pin the executable beside the rule set and verify exit codes plus JSON or SARIF consumers on every upgrade.
Docs5/5The official documentation covers syntax matching, metavariable constraints, taint mode, rule tests, ignore files, supported languages, CLI switches, output formats, metrics, editor extensions, pre-commit, CI, and hosted setup. The README plainly states the function and file boundary of Community Edition and lists paid capabilities separately. Because open and hosted features share a site, readers still need to check which engine and account tier a page describes.
Maintenance5/5Release 1.174.0 was published on August 20, 2026, and GitHub recorded another push on August 25. The repository is unarchived, has 16,396 stars, and shows 901 open issues and pull requests in the combined counter. The current release changed dependency diff reporting and partial dependency resolution. That active cadence delivers language and scanner fixes quickly, while a pinned CI version is needed to prevent surprise behavior changes.
Ecosystem5/5The supplied package count is 7,587,925 downloads per week. Semgrep scans more than 30 code languages, has a public rule Registry and Playground, integrates with editors and pre-commit, and emits common CI and security formats. The CLI can also connect to the AppSec Platform and MCP tooling. Cross-file analysis, proprietary rules, supply-chain reachability, and managed secrets remain a different product boundary from local Community Edition scans.

Use it if

  • Your team can express a forbidden call shape, unsafe data use, or migration rule more precisely as syntax than as text.
  • One checked-in rule suite must scan a repository containing several supported languages.
  • A code audit needs structural search with metavariables, exclusions, and dataflow beyond what grep can represent.
  • Rules and fixtures should run locally with source kept on the build machine.
Skip it if

Setup reality

We installed semgrep 1.174.0 in a clean Python 3.12 Bookworm sandbox. It completed in 1.8 seconds, left 66 packages, and took 316 MB on disk. The distribution declares 27 direct dependencies and requires Python 3.10 or newer. It contains compiled .so files and a py.typed marker. import semdep worked in 0.02 seconds, and pip-audit found 0 known vulnerabilities. Our package check could not identify a license.

Put the CLI in pipx, an isolated uv tool environment, or a pinned CI image instead of the application's virtualenv. semgrep scan can run local rules without an account. Hosted policy through semgrep ci needs SEMGREP_APP_TOKEN. A Registry shorthand downloads rules and may send pseudonymous metrics. For a fixed offline run, commit the rule files and add --metrics off.

CI configuration needs target paths, a reviewed .semgrepignore, an explicit baseline policy, and tested exit behavior. A scan can print findings without failing unless --error or hosted policy changes the result. Run the exact command against a fixture that must fail. Send JSON or SARIF to its own artifact file so log messages cannot corrupt machine-readable output.

Treat a rule like production code. Add positive and negative fixtures, then run semgrep --test. patterns combines conditions, pattern-not removes matching ranges, metavariables bind syntax, and fix can edit source. Large monorepos need measured memory and time limits. Community Edition's local result only covers its engine boundary; version 1.174.0 does not turn a clean single-file scan into proof that cross-file flows are safe.

Patterns

Pin Semgrep outside the app install-isolated-cli

uv tool install 'semgrep==1.174.0'
semgrep --version

The measured package declares 27 direct dependencies, so an isolated tool environment keeps them out of production imports.

Search for a self-comparison run-structural-query

semgrep -e '$X == $X' --lang py src/

Single-quote the expression because shells otherwise try to expand dollar-prefixed metavariables.

Write a Python rule ban-eval-call

rules:
  - id: forbid-python-eval
    languages: [python]
    message: Dynamic Python evaluation is forbidden
    severity: ERROR
    pattern: eval($EXPRESSION)

Pair this YAML with files containing expected matches and safe cases before CI enforcement.

Find a Flask debug launch combine-rule-patterns

rules:
  - id: flask-debug-enabled
    languages: [python]
    message: Run Flask without debug mode
    severity: ERROR
    patterns:
      - pattern-inside: |
          $APP = Flask(...)
          ...
      - pattern: $APP.run(..., debug=True, ...)

Every condition under patterns must match in compatible source ranges; ellipses permit intervening syntax.

Flag requests without a timeout exclude-timeout-calls

rules:
  - id: requests-without-timeout
    languages: [python]
    message: Add an HTTP timeout
    severity: WARNING
    patterns:
      - pattern: requests.get(...)
      - pattern-not: requests.get(..., timeout=$SECONDS, ...)

Test aliases, wrappers, and positional arguments because this rule only recognizes the written call shapes.

Constrain a captured variable filter-metavariable-name

rules:
  - id: review-secret-assignment
    languages: [python]
    message: Review this credential-like assignment
    severity: WARNING
    patterns:
      - pattern: $NAME = $VALUE
      - metavariable-regex:
          metavariable: $NAME
          regex: '(?i).*(password|secret|token).*'

The regex checks source text for the variable name; it does not prove the assigned value is a credential.

Attach a small rewrite provide-autofix

rules:
  - id: replace-debug-print
    languages: [python]
    message: Send diagnostics to the logger
    severity: INFO
    pattern: print($VALUE)
    fix: logger.info($VALUE)

Check the generated edit. Multiple arguments, formatting, and missing logger setup can make this replacement invalid.

Run without Registry metrics scan-checked-in-rules

semgrep scan \
  --config .semgrep/rules.yml \
  --metrics off \
  src/ tests/

A local config fixes the reviewed rules in the repository, and --metrics off disables Semgrep rule metrics.

Return a failing status for findings fail-ci-on-match

semgrep scan \
  --config .semgrep/rules.yml \
  --metrics off \
  --error \
  src/

Prove the CI status with one deliberately bad fixture before relying on the flag as a merge gate.

Exclude generated code ignore-generated-paths

# .semgrepignore
dist/
coverage/
vendor/
**/*.generated.js

Review the reported targets because a broad ignore pattern can silently remove first-party source from the scan.

Write findings to an artifact export-scan-json

semgrep scan \
  --config .semgrep/rules.yml \
  --json \
  --output semgrep-results.json \
  src/

Keep human logs out of semgrep-results.json so downstream parsers receive valid JSON.

Check expected rule matches test-rule-fixtures

semgrep --test .semgrep/

Fixture comments declare matching and safe lines, turning rule behavior into a test before rollout.

Alternatives

PackageRegistryPick it when
banditPyPIChoose it for a maintained set of Python security checks without a general structural rule engine.
ruffPyPIChoose it for fast Python linting, correctness checks, imports, formatting, and modernization rules.
pylintPyPIChoose it for Python-specific static checks and plugin-based project conventions.

More security guides

cryptography · pyjwt · jose · requests-oauthlib · oauthlib · dompurify · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.