Skip to content
Hugo edited this page Sep 25, 2026 · 1 revision

Rules

Findings carry a rule id, a severity (critical, high, medium, low) and a confidence (high, medium, low).

Taint flows

Reported when attacker-controlled data reaches a sensitive call without passing through a sanitizer for that kind of sink.

Rule Reached sink
command-injection Shell or process execution (os.system, subprocess with a string, …)
sql-injection A database statement (cursor.execute, SQLAlchemy text, Django raw, …). Parameters of a parameterised query are not statements.
path-traversal A file system path (open, send_file, os.remove, …)
ssrf The URL of an HTTP client request (Requests, httpx, urllib), by position or as url=. The body, headers and query parameters are not the destination.
xss An HTTP response body built without escaping
insecure-deserialization pickle, marshal, dill, jsonpickle, shelve, and the unsafe YAML loaders. yaml.load/load_all given SafeLoader or BaseLoader are not.
open-redirect An HTTP redirect target
plaintext-credential-storage A parameter named like a password stored in a database without hashing. Medium confidence, since a name is a hint.
exploitable-vulnerability An API affected by an advisory of a vulnerable requirement — see Dependencies and Advisories

Every flow is judged before it is reported: see How a Flow is Judged.

Sanitizers inside project functions

The sanitizer may sit inside a project function the data goes through — a helper that escapes before it answers, a view that redirects to reverse(...). It then protects every caller, on every path through the function where it is called.

Function summaries keep, for each parameter, the taint kinds cleared on every path from it to an external call or to the return value. A path that skips the sanitizer, or a kind it does not clear, still reaches the sink.

What a function stores into an object or a nonlocal variable is not treated that way yet.

Django template escaping

render_to_string(name, context) returns HTML in which autoescaping escaped every variable, so data reaching a response through it is not xss — if the template really escapes. On a directory check the analyzer reads the project's templates to decide.

It establishes escaping only when all of these hold:

  • it finds every template of that name under a templates directory, by the path Django uses (app/page.html), and everything those templates extend or include;
  • none marks output safe (|safe, |safeseq, {% autoescape off %});
  • none uses a tag or filter beyond Django's own, or loads a library beyond its built-ins (static, i18n, l10n, tz, cache, humanize);
  • none places a variable where HTML escaping does not protect it: a <script> or <style> block, an event handler (onclick="…"), a style attribute, a URL attribute not fixed by a relative or http(s)://host/ prefix, an unquoted attribute, or an attribute name;
  • no Python file of the project sets autoescape to False.

Escaping is never assumed where the template cannot be read. A template named by an expression, one found through a DIRS entry not named templates, one shipped by an installed package, one rendered through get_template, and Flask's Jinja2 templates all leave the flow reported as before. A single-file check reads no template.

Values that are safe by construction

Django's csrf.get_token returns a token of letters and digits whatever the request holds, so it is no injection. reverse/reverse_lazy build a local path that attacker data in their arguments or query cannot turn into another host, so they are no open redirect — but they still carry other kinds, since reverse leaves ' unquoted.

Dangerous API usage

Rule Reported call
dangerous-eval eval or exec, whatever name the file gives them
weak-crypto hashlib.md5, hashlib.sha1 and other broken algorithms
debug-enabled app.run(debug=True) on a Flask application
missing-timeout A Requests or httpx call without a timeout
insecure-tls verify=False on a Requests or httpx call, or ssl._create_unverified_context()
unsafe-xml A standard-library or lxml XML parser, which expands entities; defusedxml is the safe replacement
unsafe-archive-extraction tarfile/zipfile extraction or shutil.unpack_archive without a member filter
insecure-temp-file tempfile.mktemp, which names a file without creating it
weak-random A random function whose result is assigned to a credential-like name, or produced by a function named like one. Medium confidence.

Secrets

One finding per literal, with a redacted preview and never the secret itself, in Python sources and in configuration files.

Rule Confidence Trigger
hardcoded-secret high A provider-specific format: AWS, GitHub, Slack, Stripe, Google, private keys, JWTs, SendGrid, Twilio
hardcoded-credential medium A credential-like name (password, token, api_key, app.config['SECRET_KEY'], …) bound to a real value. Placeholders are excluded; low confidence in test code, fixtures and files such as .env.example, with the context in the metadata.
high-entropy-string low An opaque high-entropy token. Hex digests (MD5/SHA lengths, or a name such as hash, checksum, commit), subresource-integrity hashes (sha512-…) and character-set constants are not secrets unless a credential name says so.

Dependencies

Rule Trigger
vulnerable-dependency A requirement allows a version affected by an advisory, reported at its line
reachable-vulnerability A call in the project to an API the advisory affects, or a read of an entry point marked read
exploitable-vulnerability Attacker-controlled data reaches such a call. Critical.
denied-dependency A package the policy denies
unpinned-dependency A requirement without an exact pin when the policy requires pins

See Dependencies and Advisories.

Notes that are not findings about your code

Rule Meaning
unsupported-syntax A function used syntax outside the supported subset; the rest of the file was still analysed
syntax-error Python itself could not parse the file

Read them together with the coverage line before concluding a project is clean.

Clone this wiki locally