Skip to content

Add safe builtins allowlist to prevent false positives#206

Merged
thomas-chauchefoin-tob merged 8 commits intomasterfrom
safe-builtins-allowlist
Jan 22, 2026
Merged

Add safe builtins allowlist to prevent false positives#206
thomas-chauchefoin-tob merged 8 commits intomasterfrom
safe-builtins-allowlist

Conversation

@dguido
Copy link
Copy Markdown
Member

@dguido dguido commented Jan 20, 2026

Summary

  • Add SAFE_BUILTINS frozenset containing type constructors and pure functions that cannot be used for code execution
  • Modify UnsafeImportsML and UnsafeImports analyzers to check individual builtin names against the allowlist
  • Safe builtins like dict(), len(), sorted(), enumerate() no longer trigger false positives
  • Dangerous builtins like eval, exec, getattr, __import__, open remain blocked

Test plan

  • Verify test_builtins_import_bypass still catches getattr/__import__ bypasses
  • Verify new test_safe_builtins_not_flagged passes (len not flagged)
  • Verify new test_safe_builtin_dict_not_flagged passes (dict not flagged)
  • Verify new test_unsafe_builtins_still_flagged passes (getattr still flagged)
  • Verify new test_unsafe_builtin_eval_still_flagged passes (eval still flagged)
  • All 69 tests pass

Fixes #205

🤖 Generated with Claude Code

@dguido dguido requested a review from ESultanik as a code owner January 20, 2026 17:27
dguido and others added 2 commits January 20, 2026 13:55
Previously, all imports from the builtins module were flagged as
LIKELY_OVERTLY_MALICIOUS, even safe functions like dict(), len(),
sorted(), and enumerate(). This caused false positives for legitimate
pickle files.

Add SAFE_BUILTINS frozenset containing type constructors and pure
functions that cannot be used for code execution or system access.
Modify both UnsafeImportsML and UnsafeImports analyzers to check
individual builtin names against this allowlist.

Dangerous builtins like eval, exec, getattr, __import__, and open
remain blocked as they can be used for arbitrary code execution.

Fixes #205

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Format analysis.py and test_bypasses.py with ruff
- Remove mypy from pre-commit hooks (was already skipped in CI)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@dguido dguido force-pushed the safe-builtins-allowlist branch from d6c73db to 5bb072d Compare January 20, 2026 18:56
- Add BUILTIN_MODULE_NAMES constant to eliminate repeated tuple
- Move SAFE_BUILTINS from UnsafeImportsML class to fickle.py
- Update both UnsafeImportsML and UnsafeImports to use shared constants
- Removes cross-class dependency (UnsafeImports no longer references
  UnsafeImportsML.SAFE_BUILTINS)

Co-Authored-By: Claude <noreply@anthropic.com>
type() with 3 arguments dynamically creates classes, which could be
a building block in exploit chains (e.g., triggering __init_subclass__
or __set_name__ on imported base classes/descriptors). While not
directly exploitable in isolation, there's no legitimate reason for
a pickle to dynamically create classes, so we exclude it as a
defense-in-depth measure.

Co-Authored-By: Claude <noreply@anthropic.com>
Update test_unsafe_builtins_still_flagged and test_unsafe_builtin_eval_still_flagged
to assert that both UnsafeImports and UnsafeImportsML flag dangerous builtins,
rather than checking if either one does.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@thomas-chauchefoin-tob thomas-chauchefoin-tob merged commit 3d656b9 into master Jan 22, 2026
11 checks passed
@thomas-chauchefoin-tob thomas-chauchefoin-tob deleted the safe-builtins-allowlist branch January 22, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Benign functions in builtins being labelled as OVERTLY_MALICIOUS

2 participants