Skip to content

type_evaporation_scan

Detect Type System Evaporation vulnerabilities where TypeScript types are lost at API boundaries, leaving backend code vulnerable to type confusion attacks.

Quick Reference

type_evaporation_scan(
    frontend_code: str,              # TypeScript/JavaScript frontend code
    backend_code: str,               # Python/JS backend code
    frontend_file: str = "frontend.ts",  # Frontend filename
    backend_file: str = "backend.py"     # Backend filename
) -> TypeEvaporationResult

User Stories

Persona Story Tool Value
🛡️ Marcus (Security Engineer) "Detect TypeScript type safety violations at runtime boundaries" Type system integrity
🏢 Jennifer (Enterprise Architect) "Ensure type safety across frontend/backend boundaries at scale" Architectural integrity
👥 David (Team Lead) "Verify API contracts are properly validated" API safety

See all user stories

Parameters

Parameter Type Required Default Description
frontend_code string Yes - Frontend TypeScript/JavaScript code
backend_code string Yes - Backend Python or JavaScript code
frontend_file string No "frontend.ts" Frontend filename for context
backend_file string No "backend.py" Backend filename for context

What is Type Evaporation?

Type Evaporation occurs when: 1. Frontend defines strict TypeScript types for API requests 2. Types are "evaporated" (lost) when data crosses network boundary 3. Backend receives untyped any data via request.json() 4. Backend assumes types match without validation 5. Attackers send malformed data that bypasses frontend validation

graph LR
    A[TypeScript] -->|Strict Types| B[API Call]
    B -->|Network| C[Backend]
    C -->|request.json| D[Untyped Data]
    D -->|Type Confusion| E[Vulnerability]

    style B fill:#ff9
    style D fill:#f99

Response Schema

{
  "data": {
    "vulnerabilities": [
      {
        "type": "string",
        "severity": "string",
        "frontend_type": "string",
        "backend_usage": "string",
        "frontend_line": "integer",
        "backend_line": "integer",
        "description": "string",
        "recommendation": "string"
      }
    ],
    "frontend_interfaces": [
      {
        "name": "string",
        "fields": [{"name": "string", "type": "string"}],
        "line": "integer"
      }
    ],
    "backend_endpoints": [
      {
        "path": "string",
        "method": "string",
        "expects_type": "string | null",
        "validates_type": "boolean",
        "line": "integer"
      }
    ],
    "type_coverage": {
      "frontend_types": "integer",
      "backend_validated": "integer",
      "percentage": "float"
    }
  },
  "tier_applied": "string",
  "duration_ms": "integer"
}

Examples

Detect Type Evaporation

Check if our API has type evaporation vulnerabilities
// frontend.ts
interface CreateUserRequest {
  name: string;
  email: string;
  age: number;
  isAdmin: boolean;
}

async function createUser(user: CreateUserRequest) {
  const response = await fetch('/api/users', {
    method: 'POST',
    body: JSON.stringify(user)
  });
  return response.json();
}
# backend.py
@app.route('/api/users', methods=['POST'])
def create_user():
    data = request.json  # Type evaporates here!

    # Assumes 'age' is a number, but no validation
    if data['age'] >= 18:
        # If attacker sends age="18", this breaks
        create_adult_user(data)

    # Assumes 'isAdmin' is boolean
    if data.get('isAdmin'):
        # Attacker can send isAdmin="true" (string truthy)
        grant_admin_privileges(data['name'])

    return jsonify({"status": "created"})
{
  "frontend_code": "interface CreateUserRequest {\n  name: string;\n  email: string;\n  age: number;\n  isAdmin: boolean;\n}\n\nasync function createUser(user: CreateUserRequest) {\n  const response = await fetch('/api/users', {\n    method: 'POST',\n    body: JSON.stringify(user)\n  });\n  return response.json();\n}",
  "backend_code": "@app.route('/api/users', methods=['POST'])\ndef create_user():\n    data = request.json\n    \n    if data['age'] >= 18:\n        create_adult_user(data)\n    \n    if data.get('isAdmin'):\n        grant_admin_privileges(data['name'])\n    \n    return jsonify({'status': 'created'})",
  "frontend_file": "frontend.ts",
  "backend_file": "routes/users.py"
}

```bash codescalpel type-evaporation-scan \ --frontend-code "interface CreateUserRequest {

name: string; email: string; age: number; isAdmin: boolean; }

async function createUser(user: CreateUserRequest) { const response = await fetch('/api/users', { method: 'POST', body: JSON.stringify(user) }); return response.json(); }" \ --backend-code "@app.route('/api/users', methods=['POST']) def create_user(): data = request.json

if data['age'] >= 18:
    create_adult_user(data)

if data.get('isAdmin'):
    grant_admin_privileges(data['name'])

return jsonify({'status': 'created'})" \
  --frontend-file frontend.ts \
  --backend-file routes/users.py
```
{
  "data": {
    "vulnerabilities": [
      {
        "type": "TYPE_EVAPORATION",
        "severity": "HIGH",
        "frontend_type": "CreateUserRequest.age: number",
        "backend_usage": "data['age'] >= 18 (numeric comparison)",
        "frontend_line": 4,
        "backend_line": 5,
        "description": "Frontend expects 'age' as number, but backend does not validate type. Attacker can send string '18' which may cause unexpected behavior in comparison.",
        "recommendation": "Add runtime validation: isinstance(data['age'], int)"
      },
      {
        "type": "TYPE_EVAPORATION",
        "severity": "CRITICAL",
        "frontend_type": "CreateUserRequest.isAdmin: boolean",
        "backend_usage": "data.get('isAdmin') (truthy check for admin)",
        "frontend_line": 5,
        "backend_line": 8,
        "description": "Frontend expects 'isAdmin' as boolean, but backend uses truthy check. Attacker can send isAdmin='yes' (truthy string) to gain admin access.",
        "recommendation": "Validate strict boolean: data.get('isAdmin') is True"
      }
    ],
    "frontend_interfaces": [
      {
        "name": "CreateUserRequest",
        "fields": [
          {"name": "name", "type": "string"},
          {"name": "email", "type": "string"},
          {"name": "age", "type": "number"},
          {"name": "isAdmin", "type": "boolean"}
        ],
        "line": 1
      }
    ],
    "backend_endpoints": [
      {
        "path": "/api/users",
        "method": "POST",
        "expects_type": "CreateUserRequest",
        "validates_type": false,
        "line": 1
      }
    ],
    "type_coverage": {
      "frontend_types": 4,
      "backend_validated": 0,
      "percentage": 0.0
    }
  },
  "tier_applied": "pro",
  "duration_ms": 85
}

Safe Pattern Detection

from pydantic import BaseModel

class CreateUserRequest(BaseModel):
    name: str
    email: str
    age: int
    isAdmin: bool

@app.route('/api/users', methods=['POST'])
def create_user():
    data = CreateUserRequest(**request.json)  # Validated!

    if data.age >= 18:
        create_adult_user(data)

    if data.isAdmin:
        grant_admin_privileges(data.name)
{
  "data": {
    "vulnerabilities": [],
    "type_coverage": {
      "frontend_types": 4,
      "backend_validated": 4,
      "percentage": 100.0
    },
    "validation_method": "pydantic",
    "status": "SAFE"
  }
}

Vulnerability Types

Type Severity Description
TYPE_EVAPORATION HIGH Type lost at API boundary
BOOLEAN_CONFUSION CRITICAL Boolean type bypassed with truthy string
NUMBER_STRING_CONFUSION HIGH Number expected but string accepted
ARRAY_INJECTION MEDIUM Single value where array expected
NULL_INJECTION MEDIUM Null where value expected
PROTOTYPE_POLLUTION CRITICAL proto or constructor injection

Mitigation Strategies

1. Pydantic Validation (Python)

from pydantic import BaseModel, validator

class UserRequest(BaseModel):
    name: str
    age: int
    isAdmin: bool

    @validator('isAdmin', pre=True)
    def strict_bool(cls, v):
        if not isinstance(v, bool):
            raise ValueError('must be boolean')
        return v

2. Zod Validation (Node.js)

import { z } from 'zod';

const UserSchema = z.object({
  name: z.string(),
  age: z.number().int(),
  isAdmin: z.boolean().strict()
});

app.post('/api/users', (req, res) => {
  const data = UserSchema.parse(req.body);  // Throws if invalid
});

3. TypeBox (Shared Types)

// shared/types.ts
import { Type, Static } from '@sinclair/typebox';

export const UserRequest = Type.Object({
  name: Type.String(),
  age: Type.Integer(),
  isAdmin: Type.Boolean()
});

export type UserRequest = Static<typeof UserRequest>;

Tier Limits

type_evaporation_scan capabilities vary by tier:

Feature Community Pro Enterprise
Max files analyzed 50 500 Unlimited
Frontend languages TypeScript, JavaScript TypeScript, JavaScript TypeScript, JavaScript
Backend languages Python, JavaScript Python, JavaScript Python, JavaScript
Frontend-only mode ❌ (full analysis) ❌ (full analysis)
Validation detection ✅ Basic ✅ Advanced ✅ Full
Pydantic/Zod support ✅ Basic ✅ Full ✅ Full
Schema generation
Custom validators

Community Tier

  • ✅ Detect type evaporation at API boundaries
  • ✅ Parse TypeScript interfaces
  • ✅ Detect Python/JS backend usage
  • ✅ Basic validation detection (Pydantic, Zod)
  • ✅ Identify boolean confusion vulnerabilities
  • ⚠️ Limited to 50 files - Small projects only
  • ⚠️ Frontend-only mode - Can't analyze backend separately
  • ❌ No automatic schema generation
  • ❌ No custom validator detection

Pro Tier

  • ✅ All Community features
  • 500 files analyzed - Production applications
  • Full frontend/backend analysis - Separate or combined
  • Advanced validation detection - FastAPI, Flask-Pydantic, etc.
  • Enhanced type coverage metrics - Better reporting
  • Framework-specific patterns - Django REST, NestJS, etc.

Enterprise Tier

  • ✅ All Pro features
  • Unlimited files - Enterprise-scale applications
  • Automatic schema generation - Generate Pydantic/Zod from TypeScript
  • Custom validator detection - Organization-specific validators
  • Multi-repo analysis - Scan across microservices
  • Remediation code generation - Auto-generate fixes

Key Difference: File Coverage and Schema Generation - Community: 50 files, frontend-only - Basic type safety check - Pro: 500 files, full analysis - Production API validation - Enterprise: Unlimited, schema generation - Enterprise type safety

See tier comparison

Best Practices

  1. Always validate backend input - Never trust frontend types
  2. Use validation libraries - Pydantic, Zod, TypeBox
  3. Match types exactly - Don't rely on truthy checks
  4. Test with malformed data - Send strings where numbers expected
  5. Share type definitions - Single source of truth