Vibe Coding Security: What DaloyJS Already Blocks Before Your AI Even Ships
Aikido's 'WTF is Vibe Coding Security' post lists the usual suspects: SQL injection, path traversal, hardcoded secrets, unlocked admin routes, missing input sanitization, dependency rot. This post shows which of those a DaloyJS app already blocks by default, even when the code is written by a sales rep at 1am with an AI assistant, and the small list of things you still have to opt into.
A reader sent Aikido's "WTF is Vibe Coding Security" and asked which risks DaloyJS already blocks.
For the unfamiliar: vibe coding is when someone, often someone who is not a developer, describes what they want in English and ships whatever the model writes. Agentic coding is the same thing with the model also installing the dependencies, running the tests, and pushing the PR. The Aikido post lists the usual scary outcomes: SQL injection, path traversal, hardcoded secrets, an admin route left mounted on the public app (the "Tea app" story), and an AI agent that deleted a production database while "lying about unit tests" (the Replit / SaaStr story).
I read it, opened DaloyJS, and went through each risk to see what we already block, what needs one opt-in line, and where DaloyJS can't help. Below is that mapping. The TL;DR: if a sales rep uses an AI assistant to scaffold a DaloyJS app at 1am, the boring stuff, body limits, prototype pollution, header splitting, path traversal, secret-shaped logs, is on before they type their first prompt. What they still have to choose is which routes need auth and where the admin surface lives. Those are policy, not defaults.
Risk 1: SQL injection
- DaloyJS blocks
- Standard Schema (Zod / Valibot) validation lives in the route definition, not in an afterthought. A declared schema is enforced before the handler runs; a route without one still gets the raw ctx.request, so look for that in review. /docs/security/sql-injection documents the per-ORM patterns; the scaffolder ships Prisma / Drizzle / TypeORM templates that are parameterized by construction.
- You still own
- Pick a real ORM. Don't write template-string SQL. The framework will not stop you from doing the wrong thing inside your handler, but it will hand you a fully-typed, validated input object so you have no excuse.
DaloyJS doesn't ship an ORM. That's deliberate, pinning one ORM would be the same kind of opinionation that gets frameworks in trouble. What it does ship is a route shape where the input is validated before your handler runs:
And a documented path for the database layer:
Full guidance: /docs/security/sql-injection and the per-ORM pages under /docs/orm.
Risk 2: Path traversal
- DaloyJS blocks
- The router rejects '..' segments, '//', encoded NULs, and percent-encoded traversal sequences before the route is matched. Returns 404 with no handler invocation.
- You still own
- Constrain :param shapes with a Zod regex anyway. Defense in depth costs you one line.
The full list of what the router refuses to walk into is in /docs/security/runtime-protections.
Risk 3: Hardcoded secrets and AI-generated supply-chain rot
- DaloyJS blocks
- Repo-wide CI gates that block leaked credentials, base64-smuggled payloads, invisible-unicode Trojan Source, install-time lifecycle scripts in the published packages' own manifests (the #1 npm attack vector), remote exec (curl|sh, eval(fetch())), unpinned GitHub Actions, and unauthorized license categories. CycloneDX and SPDX SBOMs are generated and verified on every release, and the package is published with npm provenance. @daloyjs/core itself ships with zero runtime dependencies, there is no transitive blast radius.
- You still own
- These gates run in the DaloyJS repo. Scaffold with --with-ci to get lockfile verification, secret scanning, CodeQL, OSV and Scorecard workflows in your own project. Don't turn ignore-scripts off because a dependency 'needs' a postinstall, that's the attack.
The full reasoning behind each gate is in "Supply-chain hardening for TypeScript libraries". The shorter version: attackers do not need a 0-day if they can ship a malicious postinstall, and AI agents do not inspect scripts blocks before running npm install. Turning lifecycle scripts off (ignore-scripts) is what stops the next Shai-Hulud-style install-script worm. It does not stop a chalk-style compromise, where the payload runs when your code imports the package; the 24-hour release-age cooldown and a committed lockfile are what help there.
Risk 4, Unlocked admin routes (the "Tea app" story)
- DaloyJS blocks
- ipRestriction() and basicAuth() are first-class middleware. /docs/security/admin-panels exists specifically to argue that the safest admin route is the one that isn't mounted on the public app at all, and shows the multi-App pattern that makes that easy.
- You still own
- Pick a pattern: separate App on a separate hostname (best), or /admin mounted with ipRestriction + basicAuth (acceptable). The framework refuses to invent a default 'admin' user, there is none, so a forgotten password is not a backdoor.
The dedicated page is /docs/security/admin-panels. If the "Tea app" team had read it, they'd have shipped an internal-only deploy and the breach would not have happened. Frameworks cannot force deployment policy, but DaloyJS makes the internal-only configuration the easier path.
Risk 5: Missing input sanitization
- DaloyJS blocks
- Standard Schema everywhere (Zod, Valibot, ArkType all supported). Body, query, params, and headers are all validated against a declared schema. Unknown fields are stripped or rejected depending on your schema, the wrong type gets a 422 before the handler runs, and the validated value is what the handler's typed arguments carry.
- You still own
- Write the schema. The framework will hold the line.
This is the same pattern as Risk 1, applied to every input surface, not just bodies. The route contract is the validation layer, there is no "remember to call zod.parse" convention. If the body schema rejects, the handler never runs. The honest limit: a route that declares no body schema still gets the raw ctx.request, and nothing stops a handler from reading it, so "does this route declare its inputs?" is still a review question.
Risk 6, Agentic coding doing things the prompt didn't ask for
- DaloyJS blocks
- fetchGuard(), a guarded fetch that refuses cloud metadata, loopback, and RFC1918 targets by default. requestTimeoutMs + bodyLimitBytes, bounded resource use. Per-request structured logs with correlated request IDs go to your SIEM, so 'the AI agent did what?!' becomes a query, not an archeology dig. The scaffolder ships an AGENTS.md and a daloyjs-best-practices SKILL.md so the agent reads the rules before it writes code.
- You still own
- Don't give the production-DB password to the agent. Run agentic tools against a sandbox account. Treat AI commits like junior-dev commits, review them. The framework cannot stop you from handing your prod credentials to a model.
The "agent reads the rules before it writes code" piece is covered in "Designing for Coding Agents". The point of scaffolding AGENTS.md is exactly the "PromptBOM" idea the Aikido post pitches at the end, give the agent provenance and rules before it generates, not after.
The assume-the-vibe-coder-skipped-it defaults
The article's most useful line: "Treat AI code like a junior developer wrote it." Translated into framework defaults, that means the dangerous things have to be off when nobody remembered to turn them off. That's the constructor:
What DaloyJS does not cover
- Destructive database privileges can still ruin production from inside a handler. Give agents read replicas and least-privilege database roles.
- AI-generated business logic still needs review. Typed routes, typed clients, and OpenAPI give reviewers and SAST tools a structured surface to inspect.
- Authentication remains an explicit per-route decision because some routes are public. Daloy provides
jwk(),basicAuth(),bearerAuth(),session(), and the auth-slice pattern. - AI moderation and runtime intrusion detection need separate systems. Daloy provides the event stream a detector consumes.
A vibe-coder prompt I would actually use
That paragraph plus pnpm create daloy@latest is the entire setup. The scaffolded project ships with a hardened CI bundle (--with-ci, on by default: lockfile-source check, CodeQL, OSV, secret scanning, Scorecard), the AGENTS.md the model needs, the security docs linked from the README, and the secure-by-default constructor. The sales rep at 1am has to actively work to disable any of it.
What DaloyJS covers
DaloyJS defaults cover the common mistakes in the Aikido list even when a generated handler omits them. Application owners still have to choose an identity provider, restrict the database role, protect production credentials, and review changes.
Related reading on this blog: Cloud Security Architecture, Mapped, Secure by Default, Supply-chain hardening for TypeScript libraries, Designing for Coding Agents, Scaffolding a production-ready DaloyJS app in 60 seconds. Relevant docs: /docs/security, admin panels, SQL injection, fetch guard, runtime protections, supply chain.