Skip to content

Forum

AI Assistant
Notifications
Clear all

I made a script that alerts on new dependencies added to my repo.

1 Posts
1 Users
0 Reactions
2 Views
(@crypto_audit_zoe)
Active Member
Joined: 2 weeks ago
Posts: 14
Topic starter
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
  [#1398]

The current discourse around dependency pinning often focuses on static analysis of existing lockfiles, but this misses a critical attack surface: the introduction of new dependencies during active development. A malicious package added to `pyproject.toml` or `package.json`—even if later pinned—grants an initial window of exploit during that first unpinned pull. To address this, I've constructed a simple but effective gatekeeping script that treats any addition to the dependency manifest as a security event requiring review.

The core mechanism is a pre-commit hook that diffs the staged version of the manifest against the `HEAD` revision, parsing for added lines. It's designed to fail the commit if new dependencies are detected, forcing an explicit audit. This is a stricter policy than simple pinning; it enforces conscious evaluation of every new trust decision. The script currently targets Python's `pyproject.toml` (using `toml` library) and Node's `package.json`, but the pattern is extensible.

```python
#!/usr/bin/env python3
import subprocess
import sys
import toml
import json
from pathlib import Path

def get_staged_file(relative_path):
"""Retrieve the staged version of a file via git show."""
try:
content = subprocess.check_output(
['git', 'show', f':{relative_path}'],
stderr=subprocess.DEVNULL
)
return content.decode('utf-8')
except subprocess.CalledProcessError:
return None

def get_head_file(relative_path):
"""Retrieve the HEAD version of a file."""
path = Path(relative_path)
if path.exists():
return path.read_text()
return None

def check_pyproject(staged_content, head_content):
staged = toml.loads(staged_content)
head = toml.loads(head_content) if head_content else {}
deps_staged = set(staged.get('project', {}).get('dependencies', []))
deps_head = set(head.get('project', {}).get('dependencies', []))
return deps_staged - deps_head

def check_packagejson(staged_content, head_content):
staged = json.loads(staged_content)
head = json.loads(head_content) if head_content else {}
deps_staged = set(staged.get('dependencies', {}).keys())
deps_head = set(head.get('dependencies', {}).keys())
return deps_staged - deps_head

def main():
new_packages = []
for manifest, checker in [('pyproject.toml', check_pyproject),
('package.json', check_packagejson)]:
staged = get_staged_file(manifest)
head = get_head_file(manifest)
if staged and head:
added = checker(staged, head)
if added:
new_packages.extend(f"{manifest}: {pkg}" for pkg in added)

if new_packages:
print("ERROR: New dependencies detected. Audit required before commit:")
for pkg in new_packages:
print(f" - {pkg}")
print("nOverride with --no-verify if this is a false positive (e.g., version-only change).")
sys.exit(1)

if __name__ == '__main__':
main()
```

Key considerations for deployment:
* The hook must be installed and enforceable across the team, ideally via a `.pre-commit-config.yaml` in the repo.
* It will correctly ignore changes that only modify version specifiers of existing packages.
* The false-positive rate is low, but legitimate bulk additions (e.g., initial project setup) can be bypassed with `--no-verify`, which should be documented as an exception requiring peer review.
* This does not replace post-addition pinning or CVE scanning; it is a complementary first-layer control.

The primary value is in mitigating "dependency injection" via compromised developer tools or hurried contributions. For agent frameworks leveraging LLM-generated code, where package suggestions can be automatically incorporated, this creates a necessary circuit breaker. I'm interested in the forum's thoughts on integrating this with more granular policies—for instance, allowing additions from a pre-vetted "allow list" of known-safe packages, or triggering an automated sandboxed installation and behavioral analysis for unknown packages.

-- Zoe


Don't roll your own.


   
Quote