Tips > Ops & Security

Sanitize All User Input From Webhooks

Webhook payloads are untrusted user input.

TipIntermediate2 min read

Webhook payloads are untrusted user input. Using them directly in database queries, API calls, or shell commands opens your workflows to injection attacks including SQL injection, NoSQL injection, command injection, and server-side request forgery (SSRF).

Real-world example: A webhook receives a contact form submission and inserts it into a PostgreSQL database. An attacker submits '; DROP TABLE contacts; -- as the name field.

// BAD: Direct string interpolation into SQL
// Mode: Run Once for Each Item
const name = $input.item.json.name;
const email = $input.item.json.email;

// VULNERABLE -- never do this
const query = `INSERT INTO contacts (name, email) VALUES ('${name}', '${email}')`;
```text
```javascript
// GOOD: Sanitize and validate input, use parameterized queries
// Mode: Run Once for Each Item

function sanitizeString(input, maxLength = 255) {
  if (typeof input !== 'string') return '';
  return input
    .trim()
    .slice(0, maxLength)
    .replace(/[<>'";&|`$\\]/g, ''); // Remove dangerous characters
}

function isValidEmail(email) {
  return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email);
}

const name = sanitizeString($input.item.json.name, 100);
const email = $input.item.json.email?.trim().toLowerCase() ?? '';

if (!name || !isValidEmail(email)) {
  return [{ json: { error: 'Invalid input', rejected: true } }];
}

// Pass sanitized values to a Postgres node using parameterized queries
return [{
  json: {
    sanitizedName: name,
    sanitizedEmail: email,
    receivedAt: new Date().toISOString(),
  }
}];
```text
Then in the PostgreSQL node, use n8n's built-in parameterized query support:

```sql
-- PostgreSQL node query (parameters are auto-escaped by the node)
INSERT INTO contacts (name, email, received_at)
VALUES ($1, $2, $3)
```text
Map `$1` to `{{ $json.sanitizedName }}`, `$2` to `{{ $json.sanitizedEmail }}`, and `$3` to `{{ $json.receivedAt }}`.

> **Warning: SSRF Attacks**
>
> If your webhook accepts a URL parameter and your workflow fetches that URL, an attacker can make your server request internal resources (e.g., `http://169.254.169.254/latest/meta-data/` on AWS to steal instance credentials). Always validate and allowlist URL domains before fetching.

**Related:** [Use Docker Compose with Health Checks for n8n and PostgreSQL](../self-hosting-operations/01-use-docker-compose-with-health-checks-for-n8n-and-postgresql.md) | [Use Path Parameters in Webhook URLs for Dynamic Routing](../webhook-mastery/01-use-path-parameters-in-webhook-urls-for-dynamic-routing.md)

Want this running in your stack?

I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.