Skip to main content

On This Page

Backend Security in the AI Era: Why 'It Boots' Is Not Enough

4 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Your AI shipped a backend that boots. That is the whole problem.

Devlin Duldulao, Filipino engineer and creator of DaloyJS, argues that most backend security incidents are boring—forgotten body limits, open CORS, unvalidated fetch targets. AI agents now write the median backend code that boots and returns 200, but ships with SSRF, prototype pollution, and no rate limits.

Why This Matters

The promise of AI-generated code is speed, but the reality is a flood of insecure defaults that pass tests while remaining vulnerable. Traditional ‘be more careful’ advice does not scale to code written by non-sentient agents. The failure scale is unbounded: a single unguarded CORS or SSRF fetch can expose every state-changing route or cloud metadata credentials, as demonstrated by the Capital One breach.

Key Insights

  • SSRF attacks persist: The classic Capital One breach via cloud metadata service (169.254.169.254) is still open in unguarded fetch calls; DaloyJS fetchGuard blocks loopback, private ranges, and cloud metadata IPs by default.
  • Algorithm confusion JWT attack: Many APIs accept both HS256 and RS256, allowing attackers to use the public key as HMAC secret; DaloyJS jwk() refuses symmetric algorithms when verifying via JWKS and throws on construction.
  • Prototype pollution: express.json() with no reviver allows proto manipulation; DaloyJS strips proto, constructor, and prototype via a reviver on every body parse.
  • Supply-chain risk from AI hallucinations: ‘Slopsquatting’ attacks exploit packages AI models hallucinate (e.g., @types/superfast-json); DaloyJS scaffold ships pnpm with ignore-scripts=true and minimum-release-age=1440 (24h cooldown) to block fast-moving malicious packages.
  • Contract drift creates security holes: Runtime validators, OpenAPI docs, and frontend types diverge over time; DaloyJS uses a single Zod schema to validate, generate docs, and type clients, preventing validation gaps.

Working Examples

Complete DaloyJS app showing secure defaults: capped body, request timeout, non-wildcard CORS, rate limiting, validated body with Zod, bearer auth hook, and typed routes.

import { z } from "zod";
import {
  App,
  NotFoundError,
  bearerAuth,
  cors,
  rateLimit,
  requestId,
  secureHeaders,
} from "@daloyjs/core";
import { serve } from "@daloyjs/core/node";

const BookSchema = z.object({ id: z.string(), title: z.string() });

const app = new App({
  bodyLimitBytes: 64 * 1024, // hard cap, streamed, Content-Length checked first
  requestTimeoutMs: 5_000, // slow-loris and hung-handler protection
  openapi: { info: { title: "Bookstore API", version: "1.0.0" } },
  docs: true, // mounts GET /docs, /openapi.json, /openapi.yaml
})
  .use(requestId()) // cryptographic correlation id per request
  .use(secureHeaders()) // CSP, nosniff, frame-ancestors, COOP/CORP
  .use(cors({ origin: "https://app.example.com", credentials: true }))
  .use(rateLimit({ windowMs: 60_000, max: 120 }))
  .route({
    method: "GET",
    path: "/books/:id",
    operationId: "getBookById",
    request: { params: z.object({ id: z.string() }) },
    responses: {
      200: { description: "Found", body: BookSchema },
      404: { description: "Not found" },
    },
    handler: async ({ params }) => {
      const book = books.get(params.id);
      if (!book) throw new NotFoundError(`No book ${params.id}`);
      return { status: 200 as const, body: book };
    },
  })
  .route({
    method: "POST",
    path: "/books",
    operationId: "createBook",
    auth: { scheme: "bearer" },
    hooks: bearerAuth({ validate: (t) => t === process.env.TOKEN }),
    request: { body: BookSchema }, // unknown keys rejected, body validated
    responses: {
      201: { description: "Created", body: BookSchema },
      401: { description: "Unauthorized" },
      422: { description: "Validation error" },
    },
    handler: async ({ body }) => {
      books.set(body.id, body);
      return { status: 201 as const, body };
    },
  });

serve(app, { port: 3000 });

Practical Applications

  • Use DaloyJS fetchGuard for any outbound fetch from user-provided URLs (e.g., link summarization, webhook subscriptions) to block SSRF to cloud metadata endpoints; pitfall: naive fetch(url) that follows redirects into 169.254.169.254, bypassing single-hop checks.
  • Adopt pnpm with minimum-release-age=1440 in CI/CD to defend against slopsquatting and fast-moving malicious npm packages; pitfall: AI assistant hallucinates non-existent package names, developer installs yanked malware within hours of publish.
  • Implement single-schema contracts (Zod + OpenAPI) to prevent drift between validation and documentation; pitfall: maintaining separate validators, docs, and frontend types that silently diverge, creating injection surfaces.
  • Use boot-time refusal for dangerous configs like wildcard CORS with credentials, weak sessions, or unauthenticated stateful endpoints; pitfall: deploying insecure settings because ‘it worked in dev’ and only failing under pentest.

References:

Continue reading

Next article

LLM Solves Novel Dot Puzzle: What Next-Token Prediction Gets Wrong

Related Content