Hono, the lightweight web framework for edge runtimes like Cloudflare Workers and Deno, ships with a path traversal vulnerability in its static site generation tool, toSSG(). Attackers who control dynamic route parameters via ssgParams can craft inputs to write generated files outside the intended output directory during build time. This flaw exposes build pipelines to potential file overwrites or tampering, depending on your environment.
The vulnerability stems from how toSSG() constructs output paths. Hono derives file paths from route patterns and parameters supplied to ssgParams. Without normalization or sanitization, sequences like ../ in parameter values let paths escape the configured dir, such as ./static. Files then land in parent directories or arbitrary locations resolvable by the filesystem.
Vulnerability Mechanics
Consider this minimal example from the advisory:
import { Hono } from 'hono'
import { toSSG, ssgParams } from 'hono/ssg'
const app = new Hono()
app.get('/:id', ssgParams([{ id: '../pwned' }]), (c) => {
return c.text('pwned')
})
toSSG(app, fs, { dir: './static' })
Here, the id parameter ../pwned generates a path like ./static/../pwned/index.html, which resolves to ./pwned/index.html—outside ./static. In a real build, if parameters come from tainted sources like user-submitted data in CI/CD or config files, an attacker escalates to arbitrary writes during generation.
Hono’s SSG targets static exports for hosting on CDNs or buckets, popular for JAMstack sites. Dynamic routes with ssgParams automate multi-page generation, but Hono skips path traversal checks, unlike mature SSG tools like Next.js or Gatsby, which normalize routes rigorously.
Impact and Real-World Risks
This affects only build-time SSG, not runtime routing—traffic stays safe. But builds run in trusted environments like local machines, GitHub Actions, or Vercel, where compromises amplify damage. An attacker influencing ssgParams—say, via a malicious pull request altering a params file—could overwrite package.json, deploy scripts, or credentials in the project root.
Quantify the blast radius: Hono powers thousands of projects per npm trends, with hono/ssg in active use since 2023. A scan of public repos shows integrations in Next.js hybrids and Deno deploys. In CI, if params pull from APIs or repos (common for dynamic SSG like blog post lists), a supply-chain attack vectors in. Overwriting a dockerignore or vercel.json subtly breaks deployments; worse, targeting /.ssh/id_rsa in CI runners steals keys.
Skeptically, severity hinges on threat model. Local builds need physical access or prior compromise. CI risks rise with open-source contribs—think Dependabot PRs or forks. CVSS might score 7.5 (high) for file write, but mitigations like containerized builds cap it. Still, it echoes Log4Shell’s build-time cousins: ignore at your peril if automating SSG.
Why this matters: Edge frameworks like Hono prioritize speed over bulk, skimping on security primitives. Path traversal ranks in OWASP Top 10; here, it undermines SSG’s core promise—safe static outputs. Deployers lose isolation, risking artifact poisoning that cascades to production.
Mitigation and Forward Steps
Patch immediately if using hono/ssg—advisories imply versions pre-fix are vulnerable; check Hono’s GitHub for releases post-advisory. Manually sanitize ssgParams: reject .., /, or null bytes via regex like /[\.\u0000\/\\]/. Run builds in chroot, Docker, or with --no-root flags to confine writes.
// Safe wrapper example
function safeParams(params: Record<string, string>[]): Record<string, string>[] {
return params.map(p =>
Object.fromEntries(
Object.entries(p).map(([k, v]) => [k, v.replace(/[\.\u0000\/\\]/g, '_')])
)
)
}
Alternatives: Switch to vite-plugin-ssr or Hono’s renderer for safer prerendering. Audit params sources—hardcode where possible. Tools like path-normalize or Node’s path.resolve with basename checks add defense.
Bottom line: Validate inputs at build boundaries. Hono’s lean design invites such slips; teams building at edge scale must layer defenses. Monitor Hono releases—fix landed, but verify your stack.