Skip to content

Application-security rules

Rule-pack rigor-foundry/1.2.0 adds a bounded application-security category (prefix AS) of high-precision, AST-backed rules over tracked Python. Like every RigorFoundry rule, each AS finding is an anchored needs-evidence candidate, never a verdict: it marks a real security-relevant surface for review, not a proven vulnerability. The rules are deliberately narrow to keep false positives low; breadth is not an acceptance metric.

Rules

Rule Signal Confidence
AS001-dynamic-code-execution eval(...) or exec(...) high
AS002-shell-command-execution a shell=True keyword, os.system(...), or os.popen(...) high
AS003-unsafe-deserialization pickle.load/pickle.loads, or a yaml.load with no explicit loader high
AS004-weak-hash-primitive hashlib.md5(...) or hashlib.sha1(...) low
AS005-insecure-temporary-file tempfile.mktemp(...) high
AS006-js-dynamic-code-execution native JavaScript/TypeScript eval(...) or new Function(...) high
AS007-go-command-execution native Go exec.Command(...) or exec.CommandContext(...) high
AS008-rust-unsafe-block native Rust unsafe { … } block medium
AS009-c-unsafe-libc native C/C++ gets, strcpy, strcat, sprintf, vsprintf, system, or popen high
AS010-julia-unsafe-memory native Julia unsafe_load, unsafe_store!, unsafe_wrap, unsafe_string, unsafe_copyto!, or unsafe_pointer_to_objref medium
AS011-shell-eval-execution native shell eval builtin high
AS012-disabled-tls-verification a verify=False keyword (requests/httpx and similar) high
AS013-insecure-ssl-context ssl._create_unverified_context(...) high

AS001AS005, AS012, and AS013 are Python-AST rules. AS006AS011 are native analysis over a tree-sitter AST for JavaScript/TypeScript (.js, .jsx, .ts, .tsx), Go (.go), Rust (.rs), C/C++ (.c, .h, .cc, .cpp, .hpp), Julia (.jl), and Shell (.sh); they require the optional native extra (pip install rigor-foundry[native]) and a deployment without the extra simply produces no AS006AS011 candidate. Being AST-based, they are precise: AS006 ignores a member access such as obj.eval(x); AS007 distinguishes exec.Command from other.Command or exec.LookPath; AS008 flags a real unsafe block, not the word unsafe in a string or comment; AS009 flags an unqualified call to a dangerous libc function (a namespaced std::strcpy and a bounded snprintf are not flagged); AS010 flags a Julia unsafe_* memory intrinsic (ccall and safe calls are not flagged); and AS011 flags the shell eval builtin as a command name (not the substring elsewhere). AS012 matches a literal verify=False keyword and AS013 the ssl._create_unverified_context call, so verify=True and ssl.create_default_context are not flagged. AS008 and AS010 are medium confidence because an unsafe block or intrinsic is sometimes a reviewed, necessary abstraction; the candidate asks a reviewer to confirm its invariants.

Each candidate carries a repository-tree anchor (path, line, content SHA-256), a neutral rationale, and a concrete verification procedure — for example, prove the argument to eval is a trusted literal, pass an argument vector instead of a shell string, or switch yaml.load to yaml.safe_load for external input.

Precision and applicability

The rules match on the Python AST, not on text, so a mention inside a string or comment is not flagged, and hardened equivalents are deliberately ignored: subprocess.run([...], shell=False), yaml.safe_load(...), yaml.load(stream, Loader=SafeLoader), hashlib.sha256(...), and tempfile.mkstemp(...) produce no candidate. AS004 is low confidence because a weak hash is only a defect in a security or integrity context; a reviewer confirms whether the digest backs a security decision.

The category applies to every tracked Python file, because a security defect is not test-only. It runs as a portable control for the application-security audit domain: a repository that declares that domain required is now covered by a portable rule as well as any wired native adapter (for example the Semgrep profile), so the domain is no longer reported as uncontrolled on the portable axis alone.

Calibration

False-positive calibration against real repositories is deliberately separate work: these rules ship with safe-and-vulnerable fixtures and precise AST matching, but adjudicated false-positive and reviewer-effort evidence across adopter repositories is the maturity-lifecycle step that promotes a rule from candidate breadth to calibrated enforcement.