Your website has a front door that visitors see: the pages, the forms, the navigation. But behind that front door, there are dozens of other doors that most people never notice. These are your APIs, Application Programming Interfaces, and they are the way your website's components talk to each other and to external services.
The problem is that many of these doors are unlocked. Some are wide open. And attackers know exactly how to find them.
This article explains what APIs are in the context of a business website, why they are a security concern, how attackers discover and exploit them, and what you can do to protect yourself.
What Are APIs and Why Does Every Modern Site Have Them?
An API is a way for software components to communicate. When you fill out a contact form on a website, the form data is sent to an API endpoint on the server. When a page loads product listings, it might fetch that data from an API. When your site integrates with a payment processor, email service, or CRM, those integrations happen through APIs.
Even a simple business website typically has APIs for:
- Contact form submissions - data sent from the browser to the server.
- Search functionality - queries sent to a search endpoint that returns results.
- User authentication - login, logout, password reset endpoints.
- Content management - the CMS uses APIs to create, read, update, and delete content.
- Third-party integrations - analytics, payment processors, email marketing, chat widgets.
- Dynamic content loading - infinite scroll, filtering, sorting, pagination.
If your site runs on WordPress, Drupal, or any modern CMS, it has a full REST API exposed by default. If it uses a JavaScript framework like React or Vue, it almost certainly communicates with backend APIs. Even a "simple" site with a contact form has at least one API endpoint.
WordPress REST API: Exposing User Data by Default
WordPress ships with a full REST API enabled by default since version 4.7 (released in 2016). This API was designed to make WordPress a better platform for building applications, but it also exposes data that most site owners do not realize is public.
What the WordPress REST API Exposes
Try this on any WordPress site: navigate to /wp-json/wp/v2/users. On many sites, you will see a JSON response listing all user accounts, including usernames, display names, user IDs, and profile URLs. This information is available to anyone without authentication.
Other commonly exposed endpoints:
/wp-json/wp/v2/posts- all published posts with metadata./wp-json/wp/v2/pages- all published pages./wp-json/wp/v2/comments- comments with author information./wp-json/wp/v2/media- uploaded files with full URLs and metadata./wp-json/wp/v2/categoriesand/wp-json/wp/v2/tags- taxonomy data./wp-json/- the API discovery endpoint that lists all available routes.
Why This Matters
Username enumeration is the starting point for brute force attacks. If an attacker knows the usernames on your WordPress site (and the REST API just handed them over), they can start attempting to guess passwords. Combined with the /wp-login.php endpoint and no rate limiting or account lockout, this is a straightforward attack path.
The media endpoint can reveal files that were uploaded but not linked publicly, including internal documents, draft images, or sensitive files that someone uploaded through the WordPress media library thinking they were private.
We have discussed related risks in our article on exposed admin pages.
How to Restrict the WordPress REST API
You have several options, depending on how your site uses the API:
- Disable it entirely if your site does not need it (most brochure websites do not). Add a filter in your
functions.phpor use a security plugin to disable the REST API for unauthenticated users. - Restrict specific endpoints. Block the
/usersendpoint while leaving others accessible if needed by your theme or plugins. - Require authentication for all API requests. This is the most secure approach but may break functionality that depends on public API access.
add_filter('rest_authentication_errors', function($result) {
if (!is_user_logged_in()) {
return new WP_Error('rest_not_logged_in', 'Authentication required.', array('status' => 401));
}
return $result;
});
GraphQL Introspection Left Enabled
GraphQL is an alternative to REST APIs that is becoming increasingly common. It allows clients to request exactly the data they need in a single query. Many modern websites and applications use GraphQL for their data layer.
The Introspection Problem
GraphQL has a built-in feature called introspection that allows anyone to query the full schema of the API. This means an attacker can discover every type, every field, every relationship, and every mutation (write operation) available in your API, simply by sending a single query:
{ __schema { types { name fields { name type { name } } } } }
This is like handing an attacker a complete blueprint of your database structure and every operation your API supports. With this information, they can craft targeted queries to extract data, find sensitive fields, and discover mutations that might allow them to modify data.
What We See in Practice
During security assessments, we regularly find GraphQL endpoints with introspection enabled in production. The developers needed it during development and forgot to disable it before deployment. Or they did not know it was enabled by default in their GraphQL library.
Common findings when introspection is enabled:
- User data fields that should not be queryable (email addresses, phone numbers, internal IDs).
- Admin-only mutations that are technically accessible to any authenticated user.
- Internal types and fields that reveal business logic and data relationships.
- Deprecated fields that still work and may bypass newer security controls.
The Fix
Disable introspection in production. Every major GraphQL library provides a configuration option for this. In Apollo Server: introspection: false. In graphql-yoga: maskedErrors: true and disable introspection via plugin. This should be part of your deployment checklist.
Unauthenticated API Endpoints
Beyond WordPress and GraphQL, many custom-built websites and applications have API endpoints that lack proper authentication. This happens for several common reasons:
- Development shortcuts: Authentication was "going to be added later" and never was.
- Assumed obscurity: The developer assumed nobody would find the endpoint because it is not linked from any page. This is security through obscurity, and it does not work.
- Misconfigured middleware: The authentication middleware was applied to most routes but missed some.
- Legacy endpoints: Old API endpoints from a previous version of the application that were never properly decommissioned.
- Internal APIs exposed externally: APIs designed for internal use (between microservices) that are accidentally reachable from the internet.
Common Examples
/api/users- returns a list of all users without requiring authentication./api/export- exports data (sometimes including customer data) without access control./api/admin/settings- administrative settings accessible to unauthenticated requests./api/debugor/api/health- diagnostic endpoints that reveal server information./graphql- a GraphQL endpoint with no authentication requirement.
IDOR Vulnerabilities: When Authentication Is Not Enough
IDOR stands for Insecure Direct Object Reference. It occurs when an API uses a predictable identifier (like a sequential number) to reference objects, and does not verify that the requesting user has permission to access that specific object.
How IDOR Works
Imagine an API endpoint like /api/invoices/1234 that returns invoice details. You are logged in and requesting your own invoice. Now change the number to 1235. If the API returns someone else's invoice, that is an IDOR vulnerability.
The API checked that you are authenticated (you are logged in), but it did not check authorization (whether you have permission to access invoice 1235). This is one of the most common vulnerability types in web applications and is consistently in the OWASP Top 10.
Real Impact
IDOR vulnerabilities have caused major data breaches:
- An attacker enumerates customer records by incrementing the ID parameter, downloading the entire customer database one record at a time.
- A user modifies the user ID in an API request and gains access to another user's account settings, allowing them to change the email address and take over the account.
- An API for downloading documents uses sequential document IDs, allowing anyone to download every document in the system.
Prevention
Every API endpoint that accesses user-specific data must verify that the requesting user has permission to access that specific resource. This means checking ownership or role-based access on every request, not just checking that the user is logged in. Use UUIDs instead of sequential integers for object identifiers to make enumeration harder (but still implement proper authorization checks, as UUIDs alone are not a security measure).
Rate Limiting: The Missing Protection
Rate limiting restricts how many requests a client can make to an API within a given time period. Without it, attackers can:
- Brute force login endpoints: Try thousands of password combinations per minute.
- Enumerate data: Download your entire database by making thousands of sequential API requests.
- Denial of service: Overwhelm your server with requests, making it unavailable for legitimate users.
- Abuse expensive operations: Trigger resource-intensive API calls (like search, report generation, or email sending) repeatedly to exhaust server resources.
- Scrape content: Download all your content programmatically for competitive intelligence or content theft.
What Proper Rate Limiting Looks Like
Rate limiting should be applied differently to different endpoints based on their sensitivity and expected usage:
| Endpoint Type | Suggested Limit | Rationale |
|---|---|---|
| Login / Authentication | 5-10 attempts per minute per IP | Prevents brute force attacks |
| Password reset | 3 requests per hour per email | Prevents email bombing |
| Contact form | 5 submissions per hour per IP | Prevents spam |
| Search | 30 requests per minute per IP | Prevents data scraping |
| General API | 100 requests per minute per user | Prevents abuse while allowing normal use |
| Public content | 300 requests per minute per IP | Allows normal browsing, prevents scraping |
Return appropriate HTTP status codes (429 Too Many Requests) with a Retry-After header so legitimate clients can handle rate limiting gracefully.
API Keys in Frontend JavaScript
This is one of the most common mistakes we find during website audits. Developers embed API keys, secret tokens, and credentials directly in client-side JavaScript code. Since all JavaScript served to the browser is visible to anyone who opens the developer tools, these secrets are effectively public.
What We Find in JavaScript Source Code
- Google Maps API keys (often with billing enabled and no restrictions).
- Firebase configuration including database URLs and API keys.
- Payment processor API keys (sometimes including secret keys, not just publishable keys).
- CMS API tokens with write permissions.
- Email service API keys (SendGrid, Mailgun, etc.).
- Third-party service credentials hardcoded in configuration objects.
The Damage
When a Google Maps API key is exposed without domain restrictions, anyone can use it and run up charges on your billing account. When a Firebase database key is exposed with write permissions, anyone can modify or delete your data. When an email service API key leaks, attackers can send email from your domain, destroying your email reputation and potentially using it for phishing.
How to Fix It
- Never put secret keys in frontend code. Only publishable/public keys should be in client-side JavaScript.
- Use environment variables on the server. Keep secrets in server-side environment variables, never in code that gets shipped to the browser.
- Restrict API keys by domain. Google Cloud, AWS, and most services allow you to restrict API keys to specific domains or IP addresses. Use these restrictions.
- Proxy sensitive API calls through your backend. Instead of calling a third-party API directly from the browser, route the request through your server where the secret key is stored safely.
- Rotate exposed keys immediately. If you discover that a key has been exposed, generate a new key and revoke the old one. Do not just add restrictions to the exposed key; assume it has already been copied.
How Attackers Enumerate and Exploit APIs
Understanding how attackers find and probe APIs helps you understand what needs protection. This is not theoretical; these are techniques used daily against real websites.
Discovery Phase
Attackers use multiple methods to discover API endpoints:
- Browser developer tools: Open the Network tab and browse the site. Every API call is visible, including the full URL, request headers, request body, and response. This is the simplest and most effective discovery method.
- JavaScript source analysis: Read the site's JavaScript files. API endpoints, keys, and sometimes authentication tokens are embedded in the code.
- Common path scanning: Tools like DirBuster, ffuf, or custom scripts test common API paths:
/api/,/v1/,/graphql,/wp-json/,/rest/,/.well-known/. - Robots.txt and sitemap: Sometimes API paths are listed in robots.txt (ironically, in an attempt to tell search engines not to index them, which also tells attackers where they are).
- JavaScript source maps: If source maps are deployed to production (a common mistake), they reveal the original source code structure, including all API endpoint definitions.
- Error messages: Triggering errors on the site can reveal API paths, server technology, and internal structure.
Tools Attackers Use
- Postman: Originally a legitimate API development tool, commonly used to craft and replay API requests with modified parameters.
- Burp Suite: A professional-grade web security testing tool. The proxy feature intercepts and modifies every request between the browser and the server, allowing attackers to manipulate API calls in real time.
- cURL: The command-line HTTP client. Simple, powerful, and available on every system. An attacker can script hundreds of API calls in seconds.
- OWASP ZAP: An open-source alternative to Burp Suite with similar capabilities.
- Custom scripts: Python, Node.js, or bash scripts that automate API enumeration and exploitation. These can be written in minutes by someone with basic programming skills.
- GraphQL Voyager and GraphiQL: Tools that visualize and explore GraphQL schemas, making it easy to understand and exploit a GraphQL API with introspection enabled.
Exploitation Phase
Once an attacker has mapped your API endpoints, they test each one for:
- Authentication bypass: Can I access this endpoint without logging in?
- Authorization issues: Can I access other users' data by changing IDs?
- Input validation failures: What happens if I send unexpected data types, oversized inputs, or special characters?
- SQL injection: Can I inject SQL commands through API parameters?
- Mass assignment: Can I modify fields I should not have access to by including extra parameters in my request?
- Business logic flaws: Can I manipulate the order of operations, skip steps, or abuse business rules through the API?
How to Secure Your APIs
API security is not a single action; it is a set of practices that need to be applied consistently across all your endpoints.
Authentication
Every API endpoint that is not explicitly public should require authentication. Use standard mechanisms:
- JWT (JSON Web Tokens): Stateless tokens that encode user identity and permissions. Set reasonable expiration times (not days or weeks).
- OAuth 2.0: For third-party integrations where users authorize external applications to access their data.
- API keys: For service-to-service communication. Always rotate keys regularly and revoke compromised keys immediately.
- Session cookies: For browser-based applications. Ensure they are HttpOnly, Secure, and SameSite.
Authorization
Authentication confirms identity. Authorization confirms permission. Both are required. Implement role-based or attribute-based access control. Check authorization on every request, for every resource. Do not rely on the client to enforce access rules.
Input Validation
Validate every input on the server side. Never trust data coming from the client. Check:
- Data types (expecting a number? reject strings).
- Length limits (prevent oversized inputs).
- Format validation (email addresses, phone numbers, dates).
- Allowed values (if a field should be one of a set of values, validate against that set).
- Encoding (handle Unicode, special characters, and null bytes properly).
Rate Limiting and Throttling
Implement rate limiting on all endpoints, with stricter limits on sensitive operations. Use a combination of IP-based and user-based rate limiting. Consider using a Web Application Firewall (WAF) or API gateway that handles rate limiting at the infrastructure level.
Error Handling
API error responses should be informative enough for legitimate users but should not leak internal details to attackers:
- Use generic error messages for authentication failures ("Invalid credentials" rather than "User not found" or "Wrong password").
- Do not include stack traces, file paths, or SQL queries in error responses.
- Log detailed errors server-side for debugging, but return sanitized messages to the client.
- Use consistent error response formats across all endpoints.
HTTPS Only
All API communication must use HTTPS. No exceptions. HTTP traffic can be intercepted and modified in transit. This is not optional; it is the baseline.
CORS Configuration
Cross-Origin Resource Sharing (CORS) controls which domains can make requests to your API from a browser. A misconfigured CORS policy (like allowing all origins with Access-Control-Allow-Origin: *) can allow attackers to make API calls from their own websites using your users' authenticated sessions.
Set CORS to allow only your own domains. Be specific. Do not use wildcards in production.
API Security Testing
You cannot secure what you do not test. Regular API security testing should include:
- Automated scanning: Tools like OWASP ZAP or Burp Suite can automatically test for common vulnerabilities across all your API endpoints.
- Manual testing: Automated tools miss business logic flaws and complex authorization issues. Manual testing by someone who understands your application's logic is essential.
- Authentication testing: Verify that every endpoint that should require authentication actually does. Test with expired tokens, invalid tokens, and tokens from different users.
- Authorization testing: For every endpoint that returns user-specific data, test whether User A can access User B's data by manipulating parameters.
- Input fuzzing: Send unexpected, malformed, and malicious inputs to every parameter and observe how the API responds.
- Rate limiting verification: Actually test your rate limits by sending requests above the threshold and confirming they are blocked.
A Practical Audit Checklist
If you want to assess your own API security, start with this checklist:
- Open your website in a browser with developer tools open. Go to the Network tab. Browse through every page and click every button. How many API calls do you see? List each endpoint.
- For each endpoint, try accessing it without authentication (in an incognito window). What data does it return?
- Check for the WordPress REST API: visit
/wp-json/wp/v2/users. Can you see usernames? - Check for GraphQL: try
/graphqlwith an introspection query. Does it respond? - Look at the JavaScript source files. Are there API keys, tokens, or credentials embedded?
- Try modifying numeric IDs in API requests. Can you access data belonging to other users?
- Send 100 requests to a sensitive endpoint in quick succession. Are you rate limited?
- Check your CORS headers. What domains are allowed to make API requests?
If any of these checks reveal issues, your APIs need attention. The longer they remain exposed, the higher the likelihood that an attacker will find and exploit them.
Next Steps
API security is a specialized area that requires both technical knowledge and an understanding of your specific application. At Envestis, we perform thorough API security assessments for businesses in Lugano and across Switzerland, identifying exposed endpoints, testing authorization controls, and providing specific remediation recommendations.
If you are unsure about the security of your website's APIs, contact us for a security assessment. We will map your API surface, test for the vulnerabilities described in this article, and give you a clear report of what needs to be fixed and how.
Want to know if your site is secure?
Request a free security audit. In 48 hours you get a complete report.
Request Free Audit