Every Public Package Is a Risk. Proxy It.
Log4Shell. XZ Utils. The npm event-stream incident. Every supply chain attack started with a public package your team trusted blindly. Here's how Trunx makes every external dependency a governed artifact.
The dependency problem at scale
The average production Node.js application has over 1,000 transitive dependencies. The average container image contains 400+ packages. Your team wrote maybe 5% of that code. The other 95% came from public registries your team doesn't control and can barely audit.
When event-stream was compromised in 2018, 8 million developers downloaded a backdoored npm package. When XZ Utils was backdoored in 2024, it reached production systems before the malicious commits were spotted. In both cases, the attack vector was the same: a public package pulled directly from a public registry, with no inspection layer in between.
Proxying public registries through Trunx puts an inspection layer in front of every external dependency your team consumes.
How the proxy works
Configure Trunx as an upstream proxy for public registries — npm, PyPI, Maven Central, Docker Hub, GitHub Packages. Your team's tooling doesn't change. Only the registry URL changes:
# .npmrc — before
registry=https://registry.npmjs.org/
# .npmrc — after
registry=https://registry.company.com/npm/proxy/
When a developer runs npm install lodash, the request goes to Trunx. Trunx fetches lodash from the public registry, scans it before serving it, caches it, and returns it to the client. If the scan finds a CRITICAL CVE, the package is quarantined — the developer gets an error, not a vulnerable dependency.
The cache means this only happens once per version. Subsequent installs are served from the local cache, faster than hitting the public registry, with no external dependency.
What "scanned before serving" means
Every package that passes through the proxy goes through the same pipeline as your internal packages:
- CVE scan with Grype and Trivy
- License check against your configured blocked list
- Secrets scan for embedded credentials or API keys
- SBOM generation so every transitive dependency is documented
The result is attached to the cached version. When you ask "what version of lodash did we serve on April 5th, 2026?", you get not just the version number but its complete security posture at that point in time.
Quarantine mode: zero-trust artifact intake
For high-security environments, Trunx supports quarantine mode on proxy repositories. New versions of external packages don't become available immediately — they land in quarantine, pending security team review:
trunx quarantine list --repo proxy/npm
QUARANTINED (3 pending review):
→ lodash@4.17.22 pushed 2026-04-18T09:12:00Z 0 CVEs MIT
→ express@5.0.1 pushed 2026-04-18T11:33:00Z 1 HIGH MIT
→ @types/node@22.0.0 pushed 2026-04-18T14:02:00Z 0 CVEs MIT
trunx quarantine approve lodash@4.17.22 --reviewer alice@company.com
# → Available in proxy/npm
trunx quarantine reject express@5.0.1 --reason "CVE-2026-1337 unpatched"
# → Blocked. Developers see: "Package blocked by security policy"
This is the zero-trust model applied to dependencies. Nothing external becomes consumable without explicit review.
Policy as code with OPA/Rego
Beyond per-package decisions, Trunx lets you encode your organization's entire artifact policy in OPA/Rego — the same policy language used by Kubernetes admission controllers and cloud IAM systems.
A policy that blocks all packages with GPL licenses from the frontend repositories, requires SBOM for anything promoted to production, and prevents any package older than 2 years from entering staging:
package trunx.policy
# Block GPL in frontend repositories
deny[msg] {
input.repository == "npm/frontend"
some dep in input.artifact.sbom.packages
dep.license == "GPL-2.0"
msg := sprintf("GPL-2.0 dependency: %v", [dep.name])
}
# Require SBOM for production promotions
deny[msg] {
input.action == "promote"
input.target_stage == "prod"
not input.artifact.sbom
msg := "SBOM required for production promotion"
}
# Block stale packages in staging
deny[msg] {
input.target_stage == "staging"
age_days := (time.now_ns() - input.artifact.published_ns) / 86400000000000
age_days > 730
msg := sprintf("Package is %v days old — exceeds 2-year threshold", [age_days])
}
This policy file lives in your Git repository, alongside your application code. It's reviewed in pull requests. It's versioned. When an auditor asks "what was your artifact governance policy on March 15th?", you check out that commit.
The dependency graph: blast radius on demand
Every artifact in Trunx — internal or proxied — is part of a dependency graph. When a new CVE drops, you know immediately which of your artifacts are affected:
trunx graph impact openssl@3.0.7
Affected artifacts (5):
@platform/api-gateway@2.1.0 prod → HIGH CVE
@platform/auth-service@3.4.1 prod → HIGH CVE
@platform/worker@1.8.0 staging
nginx/nginx:1.25.3 prod → CRITICAL CVE
python:3.11-slim dev
Recommended action: rebuild affected images with openssl >= 3.1.7
When Log4Shell happened, companies with a proper dependency graph had their blast radius in minutes. Companies without one spent days grepping through repositories hoping they hadn't missed anything.
Auto-upgrade PRs
When a new version of a dependency is published and passes all gates, Trunx can automatically open a pull request in your Git repository to upgrade it:
[trunx-bot] chore(deps): upgrade lodash 4.17.21 → 4.17.22
Security: resolves CVE-2024-99999 (MEDIUM)
Breaking changes: none (patch release)
Test coverage: no change detected
SBOM diff: 0 new dependencies
The PR includes the security context, the SBOM diff, and the full CVE delta. Your developer reviews it with actual information, not just a version number bump.
The result: every dependency is a governed artifact
When Trunx proxies your public registries, the distinction between "internal package" and "external dependency" collapses from a security perspective. Every package — regardless of origin — is scanned, cached, documented, and governed by the same policy.
The public registry becomes an upstream source of untrusted packages. Your Trunx proxy becomes the source of truth for what your team actually consumes. That's the model supply chain security requires.