Commit 07c7f9b
Package scanners: close fail-open gaps in the sdist fallback and hidden-payload paths (#6359)
* Package scanners: close fail-open gaps in the sdist fallback and hidden-payload paths
Follow-up hardening on the now-blocking scanners so the enforcing gate cannot
report clean while a malicious artifact goes unscanned.
scan_packages.py
- Hidden payload: also flag a network call AND an os/subprocess exec that live
only in a blanked docstring/string of an exec/eval file (the fetch-then-run
shape of an exec(__doc__) dropper). Either alone in real code was already
covered; hidden together they are the payload.
- Pinned releases fail closed: _release_files no longer falls back to the latest
artifact when a pinned version is missing or empty, so a yanked/bad pin is an
error instead of a different file being scanned in its place.
- requires_dist is read from the pinned release's metadata, not the project-level
(latest) document, so a sdist-only pin follows its own dependency tree.
- Environment markers are evaluated (PEP 508) instead of dropping any marker that
merely contains the word extra, so default-true markers like extra != 'dev' are
kept; conservative fallback keeps a dep on any uncertainty.
- Transitive recovery is a depth-bounded worklist: a wheel dependency whose own
child is sdist-only is fetched (--no-deps) and scanned, then its children are
recovered in turn, rather than being silently skipped.
scan_npm_packages.py
- Baseline keys use the package-relative path instead of the basename, so the
same basename in a different directory is not over-suppressed.
Tests cover each case; full scripts pass AST and ruff checks.
* Address review: tighten marker scope, decoy-proof the dropper check, fail closed on missing pin metadata
- Markers: keep any dep whose marker can hold on another install target
(sys_platform == 'win32', python_version == '3.13'); only drop a marker that
depends solely on extra and is false with no extra. A scanner runs on one
target but must cover code installed on others. Pure-extra markers are
evaluated against default_environment() with extra unset.
- Hidden dropper: the network+exec docstring check now inspects the removed
(blanked) span directly, so a benign visible network or subprocess call cannot
mask a payload that still lives in a docstring. Carrier checks stay
blanked-only (an in-code carrier is already caught by the normal check), so
corpus findings are unchanged.
- requires_dist: a pinned version whose own metadata cannot be fetched recovers
nothing rather than substituting the latest release's dependency tree.
- Transitive recovery: the last-ditch direct-sdist branch also chases the
recovered package's declared deps, matching the other branches.
- npm baseline: schema bumped to v2 (package-relative keys); a pre-v2 baseline
with entries is ignored (fail closed) instead of mis-applying basename keys.
Tests cover each case; scripts pass AST, ruff, and the import-hoist verifier.
* Scanner: exclude comments from hidden-payload check, flag missing pin metadata as incomplete
Hidden network+exec detection now inspects only docstring/string spans (what exec(__doc__)/exec(<str>) can actually run), so a real exec() beside comments that mention a network and a subprocess call no longer false-positives. Missing pinned-release metadata in transitive recovery records a download_error so the --with-deps path fails closed instead of treating it as no dependencies. Adds regression tests for both.
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>1 parent 48a3a78 commit 07c7f9b
5 files changed
Lines changed: 380 additions & 55 deletions
File tree
- scripts
- tests/security
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1445 | 1445 | | |
1446 | 1446 | | |
1447 | 1447 | | |
1448 | | - | |
| 1448 | + | |
1449 | 1449 | | |
1450 | 1450 | | |
1451 | 1451 | | |
1452 | 1452 | | |
1453 | 1453 | | |
1454 | 1454 | | |
1455 | 1455 | | |
| 1456 | + | |
| 1457 | + | |
| 1458 | + | |
| 1459 | + | |
| 1460 | + | |
| 1461 | + | |
1456 | 1462 | | |
1457 | 1463 | | |
1458 | 1464 | | |
| |||
1468 | 1474 | | |
1469 | 1475 | | |
1470 | 1476 | | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
1471 | 1489 | | |
1472 | | - | |
1473 | | - | |
| 1490 | + | |
| 1491 | + | |
1474 | 1492 | | |
1475 | 1493 | | |
1476 | 1494 | | |
| |||
1483 | 1501 | | |
1484 | 1502 | | |
1485 | 1503 | | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
| 1510 | + | |
| 1511 | + | |
1486 | 1512 | | |
1487 | | - | |
| 1513 | + | |
1488 | 1514 | | |
1489 | | - | |
| 1515 | + | |
1490 | 1516 | | |
1491 | 1517 | | |
1492 | 1518 | | |
| |||
1506 | 1532 | | |
1507 | 1533 | | |
1508 | 1534 | | |
1509 | | - | |
| 1535 | + | |
1510 | 1536 | | |
1511 | 1537 | | |
1512 | 1538 | | |
| |||
1516 | 1542 | | |
1517 | 1543 | | |
1518 | 1544 | | |
1519 | | - | |
1520 | | - | |
| 1545 | + | |
| 1546 | + | |
1521 | 1547 | | |
1522 | | - | |
| 1548 | + | |
1523 | 1549 | | |
1524 | 1550 | | |
1525 | 1551 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
| 2 | + | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
0 commit comments