Webhook & API Security
How criminals exploit webhooks, leaked API keys, and rate limiting gaps to forge notifications, steal data, and bypass authentication
By Benjamin, Fraud Attacks · Updated
Webhook abuse, leaked API keys, and rate-limit bypass are the three failure modes attackers exploit at the perimeter of an API. A forged webhook can trigger order fulfillment without payment; a leaked key gives outsiders the same access as a developer; a distributed bypass slips past throttles designed for individuals. This article covers each failure mode and the cryptographic and operational controls that hold the perimeter together.
The Webhook That Paid Twice
Diego Navarro was a backend engineer at a payment processing startup when the support team escalated a merchant complaint. A furniture store said three customers had been charged but never received order confirmations. The merchant's system showed no record of the charges.
Diego checked the payment logs. The charges had processed successfully. Money had moved from customers' cards to the merchant's account. But the webhook notifications, the automated messages that tell the merchant's system "hey, a payment went through," had never arrived.
He dug into the webhook delivery logs. The notifications had been sent. To the wrong URL.
Someone had accessed the merchant's API dashboard and changed the webhook endpoint. Instead of pointing to the merchant's server at orders.furnitureshop.com/webhooks, the endpoint now pointed to a server the attacker controlled. For three days, every payment notification, including full order details, customer information, and transaction IDs, had been flowing to the attacker.
But stealing data wasn't the full play. The attacker had also started sending fabricated webhook notifications back to the merchant's system from their own server. These fake webhooks told the merchant's system that refunds had been processed (they hadn't) and that new orders were paid (they weren't). The merchant was shipping furniture based on fake payment confirmations.
The webhook URL change had been made using a valid API key. The merchant's key had been committed to a public GitHub repository six months earlier, sitting in a configuration file that an intern had pushed to a public repo during a code review.
This story is fictional, but the patterns are real.
Why This Matters
In API & Business Logic 101, you learned what APIs are and why criminals target them. In Business Logic Attacks, you saw how criminals exploit flaws in the rules that govern API behavior. This article covers a different angle: the infrastructure around APIs. Webhooks, API keys, rate limits, and the security mechanisms that protect API communications.
These aren't glamorous topics. Nobody writes headlines about a misconfigured webhook URL or a leaked API key. But infrastructure failures enable some of the most damaging API-based attacks. A leaked API key gives an attacker the same access as a legitimate developer. A forged webhook can trick a system into taking actions nobody authorized.
Understanding these attack surfaces matters because they're everywhere. Every modern application relies on APIs that communicate through webhooks, authenticate with API keys, and depend on rate limiting to prevent abuse. When any of these mechanisms fails, the consequences can be severe.
Webhook Abuse
How Webhooks Work
A webhook is a way for one system to notify another that something happened. Instead of System B constantly asking System A "did anything change?" (polling), System A sends a message to System B whenever something relevant occurs.
Think of it as the difference between constantly refreshing your email versus getting a push notification. Webhooks are the push notification for servers.
In payment processing, webhooks are critical. When a customer completes a payment, the payment processor sends a webhook to the merchant's server saying "payment succeeded for order #1234." The merchant's system then fulfills the order, sends a confirmation email, and updates its records.
Webhook Forgery
The fundamental vulnerability of webhooks is trust. When a merchant's server receives a webhook notification, how does it know the message really came from the payment processor?
If the server doesn't verify the sender, anyone who knows the webhook endpoint URL can send fabricated notifications. An attacker could send a fake "payment successful" webhook and trick the merchant into shipping goods without actually paying.
This isn't hypothetical. Webhook forgery has been used to:
- Trigger order fulfillment without payment. The attacker sends a fake payment confirmation webhook. The merchant's system processes the "order" and ships the product. The same forged-confirmation pattern shows up in wire and ACH fraud when downstream systems trust a "funds received" message that was never actually sent by the bank.
- Manipulate account balances. Fake webhooks reporting deposits or credits that never occurred.
- Trigger automated actions. Many systems use webhooks to start workflows, escalations, or notifications. Fake webhooks can trigger these inappropriately.
Webhook Signing: The Defense
The standard defense against webhook forgery is cryptographic signing. The sending system (the payment processor) creates a unique signature for each webhook using a shared secret. The receiving system (the merchant) verifies the signature before trusting the message.
Here's how it typically works (the Stripe webhook signing docs↗[1] are the canonical worked example):
- When the merchant registers for webhooks, the provider gives them a signing secret (a long random string)
- For each webhook, the provider computes an HMAC (Hash-based Message Authentication Code) using the signing secret and the webhook payload
- The provider includes this HMAC signature in the webhook's HTTP headers
- The merchant's server receives the webhook, computes its own HMAC using the same secret and payload, and compares it to the signature in the headers
- If they match, the webhook is authentic. If not, it's been forged or tampered with
HMAC signing proves two things: the webhook came from someone who knows the signing secret (authenticity), and the message wasn't modified in transit (integrity). It is the same primitive that DKIM uses for email authentication, applied to a different transport.
One implementation detail matters here: use a constant-time comparison function when checking the signature, not the language's default == or ===. A naive byte-by-byte comparison returns false as soon as it hits a mismatch, so the time it takes to fail leaks information about how many leading bytes were correct. An attacker who can submit signed requests at scale can use those timing differences to recover the signature one byte at a time. Use hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js, hash_equals in PHP, or subtle.ConstantTimeCompare in Go. These compare every byte regardless of where mismatches occur, so the timing reveals nothing.
The vulnerability in Diego's case wasn't that webhook signing was absent. It was that the attacker had the API key and could change where webhooks were sent. Signing protects against outsiders forging webhooks. It doesn't protect against an attacker who compromises the configuration itself.
Webhook URLs as an SSRF Vector
There's a second, sneakier risk tied to webhook URLs. When your platform lets merchants enter a destination URL for their webhooks, your servers will eventually make HTTP requests to whatever URL was provided. That's the entire point of a webhook. But "make a server-side HTTP request to a user-supplied URL" is the textbook definition of Server-Side Request Forgery (SSRF), classified as API7:2023 in the OWASP API Security Top 10[2].
A malicious customer can set their webhook URL to something internal, and your server will dutifully request it. Classic targets include:
http://169.254.169.254/latest/meta-data/iam/security-credentials/(the AWS EC2 instance metadata service, which by default returns temporary IAM credentials for whatever role the EC2 instance has)http://metadata.google.internal/computeMetadata/v1/(the equivalent on GCP)http://localhost:6379/orhttp://10.0.0.5:5432/(internal Redis, Postgres, or other infrastructure not exposed to the public internet)file:///etc/passwd(if the HTTP client followsfile://schemes)
If your webhook delivery service runs inside a cloud VPC and isn't restricted, a single misconfigured webhook URL can hand over cloud credentials, internal API responses, or scan results from your private network. The Capital One breach in 2019 is the canonical example of metadata-service SSRF causing catastrophic damage, though it was a WAF misconfiguration rather than a webhook.
The defenses:
- Block private IP ranges and the link-local range at the HTTP client level: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16, and the IPv6 equivalents
- Require IMDSv2↗[3] on AWS so that token-less GETs to the metadata service fail
- Resolve DNS once and pin the result to defeat DNS rebinding attacks
- Use a dedicated webhook delivery service with no access to internal networks or cloud credentials
- Reject non-HTTPS schemes (
file://,gopher://,dict://) outright
This is closely related to API10:2023, Unsafe Consumption of APIs[4], which covers the broader case of your server trusting responses from third-party endpoints without validation. The same defensive mindset applies.
Webhook Replay Attacks
Even with signing, webhooks can be vulnerable to replay attacks. If an attacker intercepts a legitimately signed webhook, they could resend it later. The signature would still be valid because the message hasn't changed.
Defenses against replay attacks include:
- Timestamp validation. Include a timestamp in the signed payload and reject webhooks older than a few minutes.
- Idempotency keys. Include a unique identifier in each webhook. The receiving system tracks which IDs it has already processed and ignores duplicates.
- Nonce values. One-time-use random values that prevent exact replay of previous messages.
API Key Management
The Most Common API Security Failure
API keys are the passwords of the developer world. They authenticate applications and grant access to services. And they are leaked constantly.
The most common ways API keys end up in the wrong hands:
Committed to source code repositories. This is how Diego's merchant lost their key. A developer puts the API key in a configuration file, pushes it to GitHub, and forgets about it. Automated scanners (including GitHub's own secret-scanning service↗[5]) constantly crawl public repositories looking for patterns that match API keys. Within minutes of a key being pushed, it can be harvested.
Included in client-side code. API keys embedded in mobile apps or JavaScript bundles are visible to anyone who decompiles the app or inspects the page source. Any key in client-side code should be considered public.
Shared through insecure channels. Keys sent via email, Slack messages, or shared documents. These channels are searchable, often backed up, and accessible to anyone with account access.
Left in environment variables on compromised servers. When a server is breached, environment variables (where keys are often stored) are one of the first things attackers extract.
Hardcoded in scripts and automation. Deployment scripts, CI/CD pipelines, and automation tools often contain credentials that were "temporarily" hardcoded and never rotated.
Key Rotation: Use It or Lose It
API keys should be rotated regularly. If a key is compromised, the damage is limited to the window between compromise and rotation. If keys are never rotated, a single leak provides permanent access.
Good key rotation practice involves:
- Generating new keys periodically (the cadence depends on the risk; monthly or quarterly is common)
- Supporting multiple active keys so the old key continues working while systems are updated to use the new one
- Revoking old keys after confirming the new key is deployed everywhere
- Monitoring for use of revoked keys as an indicator of compromise (if someone tries to use a key you revoked, they likely obtained it from a leak)
Many organizations struggle with rotation because they've lost track of where keys are used. A key embedded in three different servers, two scripts, and a partner integration is painful to rotate. This is why key management discipline matters from the start.
Principle of Least Privilege
Not all API keys should have the same permissions. A key used to read transaction data doesn't need write access. A key used by a reporting tool doesn't need the ability to change webhook URLs.
Scoping API keys to the minimum required permissions limits blast radius. If Diego's merchant had used a read-only key for their reporting integration and a separate, more restricted key for webhook configuration, the leaked reporting key wouldn't have given the attacker the ability to change webhook endpoints.
Rate Limiting: The Speed Bump
Why Rate Limits Exist
Rate limiting restricts how many API requests a client can make within a given time window. Without rate limits, APIs are vulnerable to abuse at scale.
The most common attacks that rate limiting defends against:
Credential stuffing. Testing stolen username/password pairs against a login API. Without rate limits, an attacker can test millions of credentials per hour. With rate limits, they're constrained to a speed that makes large-scale testing impractical.
Card testing. Attempting small charges with stolen card numbers to identify which cards are still active. Rate limits slow the testing process and make it easier for fraud systems to detect the pattern.
Brute force attacks. Guessing passwords, OTPs, or other secrets through exhaustive trial and error.
Data scraping. Extracting large volumes of data through repeated API calls. Rate limits make bulk extraction slow and detectable.
Denial of service. Overwhelming an API with requests to make it unavailable to legitimate users.
How Rate Limits Work
Rate limits are typically implemented as a request count per time window, applied per API key or per IP address:
- 100 requests per minute per API key (the most common approach)
- 10 login attempts per hour per IP address (more aggressive, for sensitive endpoints)
- 1,000 requests per day per free-tier account (business-level throttling)
When a client exceeds the limit, the API returns an HTTP 429 ("Too Many Requests") response. Well-designed rate limits include headers that tell the client how many requests remain and when the window resets.
Rate Limit Bypass Techniques
Sophisticated attackers don't just run into rate limits and stop. They adapt:
Distributed requests. If rate limits are per-IP, the attacker distributes requests across hundreds or thousands of IP addresses using residential proxy networks. Each IP stays under the limit, but the aggregate traffic far exceeds it.
Slow and low. Instead of blasting requests at maximum speed, the attacker sends requests at a rate just below the threshold. Slower, but avoids triggering limits entirely.
Key cycling. If rate limits are per API key, the attacker creates multiple accounts to get multiple keys. Each key stays under the limit; the total throughput multiplies.
Endpoint variation. If rate limits are per endpoint, the attacker might find alternative API endpoints that perform similar functions but have separate (or no) rate limits.
Effective rate limiting needs to account for these evasion techniques. This often means combining multiple rate limit dimensions (per-IP, per-key, per-account, and global) and implementing behavioral analysis that looks at aggregate patterns rather than individual request counts.
Key Takeaways
- Webhooks are trusted messengers that can be impersonated. Without cryptographic signing (HMAC), any attacker who knows the webhook URL can send fabricated notifications that trigger real actions.
- API keys are leaked constantly. Public repositories, client-side code, and insecure sharing are the most common vectors. Treat every API key as eventually compromised and plan accordingly through rotation and least-privilege scoping.
- Rate limiting is essential but insufficient alone. Basic rate limits slow down attackers. Sophisticated attackers bypass them through distribution, key cycling, and endpoint variation. Layered rate limiting with behavioral analysis is more effective.
- Webhook, key, and rate limit security work together. A compromised API key can change webhook URLs. Absent rate limits allow brute-force attacks on key-protected endpoints. These aren't independent concerns.
- Configuration is an attack surface. Diego's case shows that the ability to change settings (webhook URLs, notification preferences, security parameters) is as dangerous as the ability to make transactions.
What's next: The GraphQL & Modern API Attacks article covers attack techniques specific to modern API architectures, including batching abuse, introspection exploitation, and nested query attacks.
References
1. Stripe — Verifying webhook signatures↗ - The canonical worked example of HMAC-signed webhook verification.
2. OWASP API7:2023 — Server Side Request Forgery↗ - The 2023 API Top 10 entry covering SSRF in API contexts.
3. AWS — Instance Metadata Service v2 (IMDSv2)↗ - Token-based metadata access introduced specifically to mitigate SSRF against EC2.
4. OWASP API10:2023 — Unsafe Consumption of APIs↗ - Covers servers that trust upstream API responses without validation.
5. GitHub — About secret scanning↗ - Automated detection of credentials committed to public and private repositories.
Key Terms
| Term | Definition |
|---|---|
| Webhook | An automated HTTP notification sent from one system to another when an event occurs |
| HMAC | Hash-based Message Authentication Code; a cryptographic method for verifying message authenticity and integrity |
| Webhook signing | Using a shared secret and HMAC to verify that a webhook came from the expected sender |
| Replay attack | Resending a previously captured legitimate message to trigger the same action again |
| API key | A credential that authenticates an application or user to an API service |
| Key rotation | Periodically replacing API keys to limit the impact of compromise |
| Rate limiting | Restricting the number of API requests a client can make within a time window |
| Idempotency key | A unique identifier ensuring the same operation isn't processed multiple times |
| Principle of least privilege | Granting only the minimum permissions necessary for a specific function |
Test Your Knowledge
Ready to test what you've learned? Take the quiz to reinforce your understanding.
Continue learning
- API Abuse & Business LogicAPI & Business Logic 101What APIs are and why they matter for fraud, explained for analysts with no technical background
- API Abuse & Business LogicBusiness Logic AttacksHow criminals exploit mathematical errors, workflow flaws, and authorization gaps
- API Abuse & Business LogicGraphQL & Modern API AttacksAttack techniques specific to GraphQL and modern API architectures: introspection abuse, nested query attacks, batching exploits, and alias abuse
- More from Fraud BasicsFraud 101: What Is Fraud?Absolute basics for someone who has never looked at fraud: what is fraud, how is it different from other crimes, and why does it matter
- More from Money Movement & Transaction FraudPayment Systems 101: How Money Really MovesEssential foundation for understanding how ACH, wire transfers, card payments, and digital payments actually work - and why criminals target them
- More from Account TakeoverATO FundamentalsEssential foundation every fraud professional needs to know about account takeover attacks