LiteLLM v1.59.8 Supply Chain Attack: Routerly Is Not Affected
A community member (VolkanSah) opened an issue on the Routerly repository reporting a supply chain attack on the litellm PyPI package, specifically version 1.59.8. The compromised package was reported to contain a backdoor designed to exfiltrate LLM API keys through environment variables, representing a critical risk for any routing or proxy layer that handles provider credentials.
This post explains why Routerly is not affected, and what we fixed anyway.
The incident
The litellm package is a widely used Python library for calling LLM APIs with a unified interface. Version 1.59.8 on PyPI was reportedly found to contain malicious code that reads API keys from environment variables and sends them to an external server. Any Python application or DevAI toolchain that pulled this version would have silently exposed its provider credentials.
Reported details are available in GitHub issue #22 and the source referenced there.
Why Routerly is not affected
Routerly is a pure TypeScript / Node.js application. It has no dependency on litellm, no Python runtime requirement, and no PyPI package in its dependency tree. The compromised package cannot reach the Routerly codebase or any deployment of it.
This can be verified directly:
- The package manifest (package.json) lists only npm packages.
- There is no
requirements.txt, nopyproject.toml, and no Python file anywhere in the repository. - The Dockerfile uses the official
node:20-alpinebase image with no Python layer.
What the report triggered: a full security audit
Although Routerly was not affected by this specific incident, the report was an opportunity to run a complete audit. We found and fixed three unrelated vulnerabilities, all of OWASP classification:
1. SSRF via webhook URL (CWE-918)
An admin user could configure a webhook notification URL. There was no validation of the destination. A malicious or misconfigured URL could have triggered requests to internal network addresses, cloud metadata endpoints (such as 169.254.169.254), or loopback interfaces, allowing an attacker with admin access to probe the internal network.
Fix: Added a validateWebhookUrl() function that blocks RFC-1918 private ranges, loopback addresses, link-local ranges, and cloud metadata endpoints before any outbound fetch.
2. Broken access control on GET /api/settings (CWE-284)
Any authenticated user, regardless of role, could call GET /api/settings and read the full settings object, which included SMTP credentials, AWS keys, and other notification configuration secrets.
Fix: The endpoint now requires the user:write permission. Read-only users and project-scoped tokens can no longer access this endpoint.
3. Weak password hashing (CWE-916)
Dashboard user passwords were hashed with SHA-256 without a salt. This is vulnerable to rainbow table attacks: a pre-computed table of common passwords and their SHA-256 hashes can crack these instantly.
Fix: Replaced with bcrypt at cost factor 12. Existing SHA-256 hashes are transparently migrated to bcrypt on the user’s next successful login, with no forced password reset required.
Supply chain hardening
Beyond the three code vulnerabilities, we also tightened the supply chain:
- Dockerfile: replaced
npm installwithnpm ciand ensuredpackage-lock.jsonis copied before the install step, so the lockfile is enforced rather than ignored - CI pipeline: added
npm audit --audit-level=highas a required step; the build fails on any high or critical npm vulnerability - Dependabot: configured for weekly automated updates to both npm packages and the base Docker image
All changes shipped in PR #23. Test suite: 41/41 passing, 0 npm audit vulnerabilities, 0 TypeScript errors.
Recommendations for users
If you are running Routerly:
- No action is required in response to the litellm incident specifically.
- If you are on any release older than the current one, we recommend updating to pick up the three vulnerability fixes above.
- If you run Routerly in a multi-user environment where not all dashboard users are fully trusted, the CWE-284 fix is particularly relevant.
To update via Docker:
docker pull inebrio/routerly:latest
docker stop routerly && docker rm routerly
docker run -d \
--name routerly \
-p 3000:3000 \
-v routerly_data:/data \
-e ROUTERLY_HOME=/data \
--restart unless-stopped \
inebrio/routerly:latest
To update via the installer:
curl -fsSL https://www.routerly.ai/install.sh | bash
The installer detects an existing installation and presents an update option.
Reporting vulnerabilities
The SECURITY.md file in the repository describes the vulnerability reporting process, coordinated disclosure policy, and current supply chain practices. We follow a 90-day disclosure timeline for reported issues.
Sources
- GitHub issue #22: github.com/Inebrio/Routerly/issues/22
- Fix PR #23: github.com/Inebrio/Routerly/pull/23
- SECURITY.md: github.com/Inebrio/Routerly/blob/develop/SECURITY.md
- Incident reference: borncity.com/news/pypi-paket-litellm-mit-backdoor-infiziert