eresus-python-audit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited eresus-python-audit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Perform a comprehensive, depth-first security audit of Python codebases. This skill provides the complete knowledge of Bandit's 50+ security checks, organized by category and severity, plus framework-specific patterns for Django, Flask, FastAPI, and emerging ML/AI attack surfaces.
Use view_file and grep_search exclusively. No terminal commands.
requirements.txt / pyproject.toml / Pipfile for dangerous dependenciesWork through each category below. For each check, use grep_search to find all instances, then view_file to trace the data flow and confirm exploitability.
| ID | Name | Severity | What to Search |
|---|---|---|---|
| B101 | assert_used | Low | assert statements used for security checks (removed with -O flag) |
| B102 | exec_used | Medium | exec() calls — trace if input is user-controlled |
| B103 | set_bad_file_permissions | Medium | os.chmod() with overly permissive modes (0o777, 0o666) |
| B104 | hardcoded_bind_all_interfaces | Medium | Binding to 0.0.0.0 — exposes service on all interfaces |
| B105 | hardcoded_password_string | Low | Strings assigned to variables named password, secret, key, token |
| B106 | hardcoded_password_funcarg | Low | Password-like strings passed as function arguments |
| B107 | hardcoded_password_default | Low | Default parameter values containing password-like strings |
| B108 | hardcoded_tmp_directory | Low | Hardcoded /tmp paths — race conditions, symlink attacks |
| B109 | password_config_option_not_marked_secret | Low | Config options with password/secret that aren't marked as sensitive |
| B110 | try_except_pass | Low | except: pass — silently swallowing errors including security exceptions |
| B111 | execute_with_run_as_root_equals_true | Medium | Functions called with run_as_root=True |
| B112 | try_except_continue | Low | except: continue — same problem as B110 |
| B113 | request_without_timeout | Medium | requests.get/post() without timeout= parameter — DoS via hang |
assert guards authentication or authorization. If so, HIGH severity.exec() input — if user-controlled, escalate to CRITICAL (RCE).requests, httpx, urllib3, aiohttp) for timeout.| ID | Name | Severity | What to Search |
|---|---|---|---|
| B201 | flask_debug_true | High | app.run(debug=True) — enables Werkzeug debugger (RCE) |
| B202 | tarfile_unsafe_members | High | tarfile.extractall() without filter= — path traversal via tar |
debug=True is conditional on environment or always on. Check for WERKZEUG_DEBUG_PIN.tarfile.open() + extractall() from user-uploaded files = CRITICAL path traversal.| ID | Name | Severity | What to Search |
|---|---|---|---|
| B324 | hashlib | Medium | Use of md5(), sha1() for security-sensitive operations (password hashing, integrity) |
hashlib.md5() / hashlib.sha1() for password storage → escalate to HIGHrandom module instead of secrets for security tokens → HIGHstring.Template with user input → potential template injection| ID | Name | Severity | What to Search |
|---|---|---|---|
| B501 | request_with_no_cert_validation | High | requests.get(url, verify=False) — TLS downgrade |
| B502 | ssl_with_bad_version | High | ssl.SSLContext(ssl.PROTOCOL_SSLv2) or SSLv3 |
| B503 | ssl_with_bad_defaults | Medium | SSLContext with insecure default protocol |
| B504 | ssl_with_no_version | Medium | SSLContext created without explicit protocol |
| B505 | weak_cryptographic_key | High | RSA < 2048 bits, DSA < 2048 bits, EC < 224 bits |
| B506 | yaml_load | Medium | yaml.load() without Loader=SafeLoader — deserialization RCE |
| B507 | ssh_no_host_key_verification | High | Paramiko set_missing_host_key_policy(AutoAddPolicy) |
| B508 | snmp_insecure_version | Medium | SNMPv1/v2 without authentication |
| B509 | snmp_weak_cryptography | Medium | SNMPv3 with weak crypto |
verify=False is in production code → CRITICAL.| ID | Name | Severity | What to Search |
|---|---|---|---|
| B601 | paramiko_calls | Medium | Paramiko SSH command execution — trace if command is user-controlled |
| B602 | subprocess_popen_with_shell_equals_true | High | subprocess.Popen(cmd, shell=True) — command injection |
| B603 | subprocess_without_shell_equals_true | Low | subprocess.Popen(cmd) without shell — still check input |
| B604 | any_other_function_with_shell_equals_true | Medium | Any function with shell=True parameter |
| B605 | start_process_with_a_shell | High | os.system(), os.popen() — command injection |
| B606 | start_process_with_no_shell | Low | os.execl(), os.execve() — still trace input |
| B607 | start_process_with_partial_path | Low | Process started without full path — PATH hijacking |
| B608 | hardcoded_sql_expressions | Medium | SQL strings built with + or % or f-strings |
| B609 | linux_commands_wildcard_injection | High | Commands with * glob — wildcard injection (tar, chown, etc.) |
| B610 | django_extra_used | Medium | Django QuerySet.extra() — raw SQL injection |
| B611 | django_rawsql_used | Medium | Django RawSQL() — raw SQL injection |
| B612 | logging_config_insecure_listen | Medium | logging.config.listen() — arbitrary code execution |
| B613 | trojansource | High | Unicode bidirectional control characters — trojan source attack |
| B614 | pytorch_load | High | torch.load() — uses pickle internally, RCE if untrusted |
| B615 | huggingface_unsafe_download | High | HuggingFace model downloads without safety checks |
tar cf archive.tar * in /tmp with user-created files → argument injection.torch.load() from user-uploaded model file → CRITICAL RCE via pickle.trust_remote_code=True.| ID | Name | Severity | What to Search |
|---|---|---|---|
| B701 | jinja2_autoescape_false | High | jinja2.Environment(autoescape=False) — stored/reflected XSS |
| B702 | use_of_mako_templates | Medium | Mako templates — no auto-escaping by default |
| B703 | django_mark_safe | Medium | mark_safe(user_input) — bypasses Django auto-escaping |
| B704 | markupsafe_markup_xss | Medium | Markup(user_input) — bypasses escaping |
autoescape=False and template renders user input → CRITICAL XSS.mark_safe(). If user-controlled → HIGH XSS.ALLOWED_HOSTS configuration (empty = open redirect)CSRF_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE, SECURE_BROWSER_XSS_FILTER@csrf_exempt decorators on sensitive viewsDEBUG = True in production settingsSECRET_KEY hardcoded or in version controlMIDDLEWARE ordering (SecurityMiddleware should be first)AUTH_PASSWORD_VALIDATORS configurationSECRET_KEY generation (must be cryptographically random)app.run(debug=True) in production@app.before_request authentication enforcementSESSION_COOKIE_SECURE, SESSION_COOKIE_HTTPONLY)werkzeug.utils.secure_filename)Body(), Query(), Path() without constraints)allow_origins=["*"])Depends())FileResponse / StreamingResponse path traversaltorch.load() — pickle-based, RCE from untrusted modelstransformers.pipeline(trust_remote_code=True) — arbitrary code executionpickle.loads() in model serialization pipelines| Confidence \ Severity | LOW | MEDIUM | HIGH |
|---|---|---|---|
| HIGH | Info | Medium | Critical |
| MEDIUM | Low | Medium | High |
| LOW | Info | Low | Medium |
For each finding, report:
### [B-ID]: [Check Name]
**Severity**: [LOW/MEDIUM/HIGH/CRITICAL]
**Confidence**: [LOW/MEDIUM/HIGH]
**File**: [path]:[line]
**Vulnerable Code**:
[show the code]
**Data Flow**:
[source] → [intermediaries] → [sink]
**Impact**: [what an attacker achieves]
**Remediation**: [specific fix with code example]
**Bandit Reference**: B[xxx]Use ONLY:
view_file — read source codegrep_search — find patterns across the codebaseDo NOT use any terminal commands.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.