Skip to content

Security Review

Farhad Davaripour edited this page Sep 15, 2026 · 4 revisions

Security and contributor review — September 14, 2026

Scope: issue #3, reviewed main 9e2b2c8080e7b3e0e728fc1200c52c6e200ec550; fixes on fd/3_Contributor_Hardening in PR #4. The public study remains Qwen3.5-0.8B only. Frozen scenario splits, model bundles, vectors, result records, manuscript claims and numerical tolerances are unchanged.

Confirmed findings

Finding Resolution and regression evidence
F1: new files ignored Removed maintained-directory filename allowlists; disposable Git tests verify normal add/status visibility for modules, configs, docs and tests. Local historical material was moved outside maintained source.
F2: tests silently omitted Unknown test ownership, stale registrations and duplicate registrations cause collection errors before imports. New top-level and nested failing tests are exercised under light/all.
F3/F4: output and temporary clobbering Outputs restricted to release/*.zip; tracked collisions, symlinks and existing outputs are refused. Exclusive writer lock and random temporary file; injected failure preserves prior valid archive. Linux CI exercises symlinks; unsupported Windows symlink tests explicitly skip.
F5: uncommitted release contents Archives read selected blobs from committed HEAD and embed source commit/content hashes. Working-tree edits and ignored local settings are excluded.
F6: integer overflow Exact Python integer subtraction; reject mixed integer/float inputs and unsupported dtypes. Boundary/optimization regressions preserve the 1e-7 reference tolerance.
F7: non-finite features Centering overflow raises an explicit error; input arrays remain unchanged.
F8: offline onboarding Concise CONTRIBUTING/SECURITY guides travel with source and wheel; longer documentation stays in the wiki per project policy. Tested CPU-small feature example is included.

Additional fixes: strict configuration values and JSON records, atomic record writes, required reproduction inventory, duplicate-key/digest checks, network-blocked replay, local manuscript asset containment, and generated LaTeX links to the retained PNGs. Source hashes are checked before figure regeneration rather than rewritten to accept changed evidence.

Dependency and CI audit

pip-audit 2.10.1 queried PyPI advisories against complete dependency sets resolved by pip dry-run with --ignore-installed --report. Resolver output, not just direct requirements, produced the audit inputs. Reviewed sets: lightweight 7 packages; reproduction 8; paper 15; research 87. No known advisory findings in these dated sets. This is not a guarantee against unpublished defects; installer/build tools and subsequently changed environments require fresh audits.

PyTorch's GHSA-63cw-57p8-fm3p affects <=2.9.1 and is patched >=2.10.0. The optional dependency floor now excludes that affected range. The recorded 2.13.0+cpu reference stays unchanged. CPU wheels now use exact official URLs and SHA256 fragments for Python 3.12 x86-64 Windows/Linux; other packages resolve from PyPI alone. Resolving after this source change produced the identical 87-package research graph.

Actions are pinned to full upstream commit IDs verified from official tag refs. CI uses contents:read, nonpersisted checkout credentials, job timeouts, cancellation of superseded runs, and no privileged pull_request_target workflow. Dependabot proposes updates. Static/advisory checks run without project credentials.

Static and secret review

Bandit 1.9.4 inspected retained Python source, including frozen native files. No medium/high finding was reported. Low findings are the historical assertion checks (inspection-only sources), subprocess imports, and fixed-argument calls to the selected Python executable or Git. No shell=True or interpolation into a shell command is used by maintained release/replay code. Tests intentionally contain assertions and disposable subprocess fixtures.

Gitleaks 8.30.1, downloaded from its official release and verified against the published SHA256, scanned all reachable history (git --log-opts=--all --redact): 879 commits, about 761 MB. It reported 10,429 generic-key heuristics. Triage identified scientific SHA256 metadata, Git/tokenizer revisions, case identifiers, Python imports/prose, and ephemeral local owner-lock UUIDs. No provider credential was confirmed. A separate current public-tree scan reported one false positive: the frozen AutoTokenizer, Qwen3_5ForConditionalGeneration import. Reports were redacted; no token values are published. No history rewrite or credential rotation was performed based on these false positives.

Release/current-tree checks must be repeated for new releases. Example commands (write outputs under ignored release/):

python -m bandit -r src reproduce paper -ll
python -m pip_audit
gitleaks git --log-opts=--all --redact --report-format json --report-path release/history-scan.json
gitleaks dir release/unpacked-public-archive --redact

Trust boundaries and residual decisions

Cached replay disables NumPy pickle, opens no network connections in the regression test, and needs no model credentials. A hash verifies integrity relative to a trusted manifest, not authenticity. Native loading explicitly disables remote model code; reviewed model/lens revisions and patched libraries remain necessary. Frozen native files are inspection-only and are not silently promoted to supported standalone runners.

Release directories must be owned by the caller; same-user adversaries or replacement of parent directories are outside this local-tool threat model. The packager rejects previous-format hash sidecars beside a requested output to prevent stale archive/hash pairs. Move the old archive/sidecar aside or choose a new name explicitly. It does not promise byte-identical ZIPs.

Main was observed unprotected and the ruleset list empty. Repository settings were not changed. Owner decisions still tracked in issue #3: require the CI jobs/review before merge, prevent force pushes, and establish a private vulnerability-reporting route. No verified private channel is claimed. Do not post suspected secrets publicly.

Resolved inventories

Light

pytest==9.1.1
ruff==0.16.7
colorama==0.4.6
iniconfig==2.3.0
packaging==26.3
pluggy==1.6.0
Pygments==2.21.0

Reproduction

cloudpickle==3.1.2
joblib==1.6.0
narwhals==2.26.0
numpy==2.5.3
scikit-learn==1.9.1
scipy==1.18.1
threadpoolctl==3.6.0
xgboost==3.4.1

Paper

charset-normalizer==3.5.1
contourpy==1.4.0
cycler==0.12.1
fonttools==4.65.0
kiwisolver==1.5.1
matplotlib==3.11.2
numpy==2.5.3
packaging==26.3
pillow==12.3.0
pymupdf==1.28.2
pyparsing==3.3.2
pypdf==6.18.1
python-dateutil==2.9.0.post0
reportlab==5.0.1
six==1.17.0

Research

Jinja2==3.1.6
MarkupSafe==3.0.3
PyYAML==6.0.3
Pygments==2.21.0
accelerate==1.15.0
aiohappyeyeballs==2.7.1
aiohttp==3.14.3
aiosignal==1.4.0
annotated-doc==0.0.5
annotated-types==0.8.0
anyio==4.15.1
attrs==26.1.0
beartype==0.22.9
better-abc==0.0.3
certifi==2026.7.22
charset-normalizer==3.5.1
click==8.5.0
colorama==0.4.6
datasets==5.0.1
dill==0.4.1
einops==0.8.2
fancy-einsum==0.0.3
filelock==3.32.6
frozenlist==1.8.0
fsspec==2026.6.0
googleapis-common-protos==1.75.3
h11==0.16.0
hf-xet==1.6.0
httpcore==1.0.9
httpx==0.28.1
huggingface_hub==1.28.0
idna==3.19
iniconfig==2.3.0
jaxtyping==0.3.11
markdown-it-py==4.2.0
mdurl==0.1.2
mpmath==1.3.0
multidict==6.8.0
multiprocess==0.70.19
networkx==3.6.1
numpy==2.5.2
opentelemetry-api==1.44.0
opentelemetry-exporter-otlp-proto-common==1.44.0
opentelemetry-exporter-otlp-proto-http==1.44.0
opentelemetry-proto==1.44.0
opentelemetry-sdk==1.44.0
opentelemetry-semantic-conventions==0.65b0
packaging==26.3
pandas==3.0.5
pillow==12.3.0
platformdirs==4.11.8
pluggy==1.6.0
propcache==0.5.2
protobuf==7.36.1
psutil==7.2.2
pyarrow==25.0.1
pydantic==2.13.5
pydantic_core==2.46.5
pytest==9.1.1
python-dateutil==2.9.0.post0
regex==2026.9.10
requests==2.34.2
rich==15.0.0
ruff==0.16.3
safetensors==0.8.0
sentencepiece==0.2.2
setuptools==84.0.0
shellingham==1.5.4
six==1.17.0
sympy==1.14.0
tokenizers==0.22.2
torch==2.13.0+cpu
torchvision==0.28.0+cpu
tqdm==4.70.1
transformer-lens==4.0.0b1
transformers-stream-generator==0.0.5
transformers==5.15.1
typeguard==4.6.0
typer==0.27.2
typing-inspection==0.4.4
typing_extensions==4.16.0
tzdata==2026.4
urllib3==2.7.0
wadler_lindig==0.1.7
wandb==0.30.0
xxhash==4.0.1
yarl==1.24.5

Final verification

PR #4 merged as 9ab40af4797a3c34fe671b427cca78aab7d42821. The tested feature revision was f7042a3a93f9f3c6a4aa47439c78291beb6fbc50. Fresh Python 3.12 checkout: 90 tests passed, two unsupported Windows symlink tests skipped; Linux CI exercised the symlink cases. All five feature CI jobs passed. Full cached replay, three refits, 640 tuning fits, figures, source audit, PDF rendering, committed release packaging, wheel and sdist builds passed. The wheel contains 10 maintained modules and all offline guides; isolated import and CLI smoke tests passed outside the repository without tensor dependencies.

Measured line coverage in the fresh combined suite: configuration 77.2%, feature strategies 95.7%, I/O helpers 64.1%. Coverage is evidence of exercised paths, not proof of native inference correctness. No new CPU/GPU model inference was performed. Protected artifact and manuscript-claim diffs were empty; the generated LaTeX changed only five figure extensions to the retained PNG files.

Post-merge verification: all five CI jobs passed on main commit 9ab40af4797a3c34fe671b427cca78aab7d42821 (CI run). The temporary verification clone and wheel-test environment were recycled after results were recorded.

Subsequent reporting scope: issue #12 narrows the public steering report to the Simplified vector and documents a derived GPU subset. Earlier preservation statements on this page refer to the dated commit reviewed above.

Clone this wiki locally