Semgrep
Semgrep is a fast, open-source, static analysis engine for finding bugs, detecting vulnerabilities in third-party dependencies, and enforcing code standards across over 30 programming languages. It scans code locally, without uploading it to external servers by default. As of version 1.156.0, it is actively developed with frequent (often weekly) releases, offering both a free Community Edition and a commercial AppSec Platform with enhanced features.
Warnings
- breaking The experimental and undocumented `semgrep install-ci` command was removed.
- breaking Connecting to the Semgrep MCP server via streamableHttp now requires OAuth.
- gotcha The default memory policy for Semgrep's engine was changed from 'eager' to 'balanced'. This may alter performance characteristics and resource usage for some scans.
- gotcha By default, `semgrep scan` and `semgrep ci` commands exit with code 0 even if findings are present. This can lead to silent failures in CI/CD pipelines.
- gotcha Semgrep Community Edition (OSS) may miss many true positives for security vulnerabilities, especially those requiring cross-file, cross-function, or data-flow analysis.
Install
-
pip install semgrep
Imports
- subprocess
import subprocess
Quickstart
import subprocess
import json
import os
# Create a dummy Python file to scan for demonstration
dummy_code = """
import os
def vulnerable_function(user_input):
# This pattern (os.system with user input) is often flagged by security rules
os.system(f"echo {user_input}")
def harmless_function():
print("Hello, Semgrep!")
"""
file_path = "vulnerable_app.py"
with open(file_path, "w") as f:
f.write(dummy_code)
print(f"Created {file_path} for scanning.")
try:
# Run Semgrep scan on the dummy file with a common security ruleset
# Use --json for machine-readable output and --error to get a non-zero exit code on findings
# `check=False` is used to allow inspection of output even if Semgrep exits with findings (code 1)
result = subprocess.run(
["semgrep", "scan", "--config", "p/security-audit", file_path, "--json", "--error"],
capture_output=True,
text=True,
check=False
)
print("\n--- Semgrep CLI Output (stdout) ---")
print(result.stdout)
if result.stderr:
print("\n--- Semgrep CLI Error (stderr) ---")
print(result.stderr)
if result.returncode != 0:
print(f"\nSemgrep exited with non-zero code: {result.returncode}. This indicates findings or an actual error.")
else:
print("\nSemgrep exited with code 0. No findings or --error was not used/no blocking rules.")
# Parse JSON output if available
try:
json_output = json.loads(result.stdout)
if json_output.get("results"):
print(f"\nFound {len(json_output['results'])} security findings:")
for finding in json_output["results"]:
print(f" - Rule: {finding['check_id']} at {finding['start']['line']}:{finding['start']['col']}")
print(f" Message: {finding['extra']['message']}")
else:
print("\nNo findings reported in JSON output.")
except json.JSONDecodeError:
print("\nCould not decode JSON output.")
except FileNotFoundError:
print("Error: 'semgrep' command not found. Please ensure Semgrep is installed and in your PATH.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
# Clean up the dummy file
if os.path.exists(file_path):
os.remove(file_path)
print(f"\nCleaned up {file_path}.")