What Is Attack Surface?
The total set of points where an attacker can try to enter or extract data from a system. This includes every API endpoint, open port, login form, file upload, third-party integration, and piece of infrastructure reachable from the outside.
How It Works
An attacker mapping your attack surface follows a systematic discovery process before choosing an exploitation path. Every step uses publicly available tools and leaves traces only in your access logs — if you are collecting them.
Step 1: Passive reconnaissance — The attacker begins without touching your servers. They query certificate transparency logs at crt.sh to enumerate every SSL certificate issued for your domain and its subdomains. They search Shodan and Censys for historical port scan data. They look for public GitHub repositories containing your .env.example, CI/CD pipeline files, or Composer configuration that reveals your framework version and packages.
Step 2: DNS enumeration — Tools like subfinder, amass, and dnsx query public DNS resolvers, brute-force common subdomain names (staging, api, admin, dev, mail, beta), and harvest results from search engines. Every discovered subdomain is added to the target list and checked independently.
Step 3: Port and service scanning — nmap -sV yourdomain.com identifies which ports are open and what services are running. Open Redis on port 6379, MySQL on 3306, or Memcached on 11211 are high-value findings that indicate internal services accidentally exposed to the internet.
Step 4: Web path discovery — The attacker probes for known Laravel paths using wordlist tools: /telescope, /horizon, /_ignition/health-check, /.env, /.git/HEAD, /api/documentation, /storage. Each successful response reveals another entry point.
Step 5: Header fingerprinting — curl -I https://yourdomain.com reveals framework signals via X-Powered-By, missing security headers, and web server identity from the Server header. This information is used to identify which known CVEs apply to the specific versions running.
Step 6: Error triggering — Visiting a non-existent route checks whether APP_DEBUG=true is active. If so, the Ignition error page exposes environment variables, database credentials, full stack traces, and file paths — handing the attacker a complete map of application internals.
Step 7: Third-party asset mapping — S3 bucket URLs found in HTML source, CDN origins in response headers, webhook endpoints in JavaScript, and embedded third-party API URLs all extend the attack surface beyond the primary domain to infrastructure the development team may not consider "part of the application".
Types of Attack Surface
Passive Reconnaissance
Attacker maps the attack surface using public sources — crt.sh, Shodan, GitHub — without sending a single request to the target, leaving no trace in access logs.
subfinder -d yourapp.com -silent | httpx -silent
Active Scanning
Attacker probes the live target with port scanners and URL brute-force tools to enumerate all reachable services and application paths.
nmap -sV -p 80,443,6379,3306,5432 yourapp.com
Supply Chain Discovery
Attacker reviews publicly available Composer lock files or CI configuration to identify framework and dependency versions, then targets known CVEs for those versions.
cat composer.lock | python3 -c "import json,sys; [print(p['name'],p['version']) for p in json.load(sys.stdin)['packages']]"
Infrastructure Discovery
Attacker enumerates cloud assets such as S3 buckets, CloudFront distributions, and unlinked admin panels that extend the attack surface beyond the primary web application.
aws s3 ls s3://yourapp-uploads --no-sign-request
In Laravel Applications
In a Laravel application, the attack surface includes all registered routes, exposed debug tools (Telescope, Ignition, Horizon), .env files, storage directories, DNS records, security headers, and open ports on the server.
Code Examples
Telescope Exposed vs. Environment-Gated
Vulnerable
// No protection — anyone can visit /telescope in production
// All HTTP requests, SQL queries, jobs, and logs are visible
// Default state if TelescopeServiceProvider is registered unconditionally
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
// Telescope registered for all environments — VULNERABLE
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
}
}
Secure
// config/telescope.php — restrict by authenticated email
'gate' => function (Request $request) {
return in_array($request->user()?->email, [
'admin@yourapp.com',
]);
},
// AppServiceProvider — only register in non-production environments
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
if ($this->app->environment('local', 'staging')) {
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
}
}
}
Nginx Document Root: Project Root vs. public/
Vulnerable
# Nginx root points to project root — .env, artisan, composer.json
# are all directly web-accessible at https://yourapp.com/.env
server {
listen 443 ssl;
server_name yourapp.com;
root /var/www/yourapp; # VULNERABLE: project root
index index.php;
}
Secure
# Nginx root points to public/ — only intended web assets are served
# .env, artisan, composer.json are never reachable via HTTP
server {
listen 443 ssl;
server_name yourapp.com;
root /var/www/yourapp/public; # SECURE: public subdirectory
index index.php;
}
Real-World Example
A Laravel app with 50 routes, an exposed Telescope dashboard, and an open Redis port has a larger attack surface than one with 50 routes, Telescope disabled, and Redis firewalled.
Why It Matters
Every feature you add to a Laravel application — a new route, a file upload endpoint, a third-party Composer package, a queued job — expands the attack surface. Developers often think only about the happy path, but attackers think about every possible entry point. A single overlooked route or misconfigured middleware can become the entry point for a breach.
In practice, Laravel applications accumulate attack surface faster than most frameworks because the ecosystem encourages rapid feature development. php artisan make:controller, php artisan make:migration, adding guzzlehttp/guzzle — each of these introduces new code paths that need to be considered from a security standpoint.
One of the biggest hidden attack surface contributors is developer tooling left running in production. Laravel Telescope (/telescope), Ignition (/_ignition), and Horizon (/horizon) all have web interfaces that can expose sensitive data if not properly guarded with middleware.
Reducing attack surface means regularly auditing php artisan route:list to check for routes that should not be public, ensuring debug tools are behind auth middleware, and removing packages from composer.json that are no longer used.
Common Misconceptions
Myth: We only have 20 routes so our attack surface is small.
Reality: Route count is one factor. Exposed ports, DNS records, debug tools, third-party integrations, and open S3 buckets all contribute to attack surface regardless of route count.
Myth: Our firewall protects us, so the attack surface is limited.
Reality: Firewalls block network-level access but do not address web application attack surface: your public routes, form inputs, API endpoints, and file uploads are all reachable through the firewall on port 80/443.
Myth: Attack surface only matters for apps with sensitive data.
Reality: Even apps without sensitive data can be exploited for server resources (crypto mining), as a stepping stone to other systems, or to damage your brand.
How to Detect This
StackShield continuously crawls your application from the outside and maps all externally reachable endpoints, DNS records, open ports, and active subdomains. To manually audit your Laravel attack surface, run `php artisan route:list --json` to enumerate all registered routes and check which ones lack auth middleware. Use `nmap -sV yourdomain.com` to discover open ports, and check your DNS records using `dig yourdomain.com ANY` or your DNS provider's dashboard. Verify that Telescope, Horizon, and Ignition are not publicly accessible by visiting `/telescope`, `/horizon`, and `/_ignition/health-check` without being logged in.
How to Prevent This in Laravel
-
1
Run `php artisan route:list --json` after every deployment and verify each sensitive route has `auth` or `auth:sanctum` in its middleware column.
-
2
Gate Telescope access by email in `config/telescope.php` and only register `TelescopeServiceProvider` in non-production environments inside `AppServiceProvider::register()`.
-
3
Set your Nginx or Apache `root` directive to your project's `public/` directory, never the project root, so `.env` and `artisan` are never web-accessible.
-
4
Remove unused Composer packages with `composer remove vendor/package` and run `composer audit` to check remaining packages for known CVEs.
-
5
Run `nmap -sV yourdomain.com` quarterly and ensure only ports 80 and 443 are open; firewall Redis, MySQL, and other internal services from external access.
-
6
Set `expose_php = Off` in `php.ini` to stop advertising the PHP version in `X-Powered-By` response headers.
Frequently Asked Questions
How do I see all routes in my Laravel application, including their middleware?
Run `php artisan route:list` in your terminal. Add `--path=api` to filter API routes, or `--json` for machine-readable output you can pipe to `jq`. Each row shows the HTTP method, URI, controller action, and middleware stack. Any route handling sensitive operations without `auth` in its middleware column is a potential unprotected entry point in your attack surface.
Does adding more features always expand the attack surface?
Yes — every new route, file upload endpoint, Composer package, or third-party integration adds to the attack surface. This does not mean you should avoid features; it means each addition deserves a security assessment. A read-only API endpoint protected by `auth:sanctum` adds minimal risk, while a file upload endpoint without MIME validation adds significant risk requiring additional controls.
Should I completely disable Telescope in production?
The safest approach is to not register Telescope in production at all — wrap the `TelescopeServiceProvider` registration in `AppServiceProvider::register()` with an `$this->app->environment('local', 'staging')` check. If you genuinely need Telescope in production for debugging, restrict access via the email-based gate in `config/telescope.php` and set `TELESCOPE_ENABLED=false` in your production `.env` by default, enabling it only when actively debugging.
How does StackShield map my attack surface?
StackShield crawls your application from the outside on each deployment and on a continuous schedule, discovering all reachable endpoints, DNS records, open ports, and active subdomains exactly as an attacker's reconnaissance would. It compares each scan against your established baseline and alerts you whenever new entry points appear — such as a newly exposed debug tool or a freshly created subdomain — so you can assess and address them before an attacker does.
Related Terms
Attack Vector
A specific method or path an attacker uses to exploit a vulnerability and gain unauthorized access to a system. While the attack surface is the total collection of entry points, an attack vector is the specific technique used against one of those entry points.
External Attack Surface Management (EASM)
The continuous process of discovering, monitoring, and managing all internet-facing assets and their security posture from an external perspective. EASM tools scan your applications the way an attacker would, identifying exposed services, misconfigurations, and vulnerabilities visible from the outside.
Vulnerability
A weakness in a system that can be exploited by an attacker to perform unauthorized actions. Vulnerabilities can exist in code, configuration, infrastructure, or processes. They range in severity from informational to critical.
Related Articles
OWASP Top 10 for AI Agents: What Laravel Teams Using the AI SDK Need to Know
OWASP released a new Top 10 for Agentic Applications in 2026, and Laravel 13 ships with a first-party AI SDK. This guide covers the intersection: prompt injection, excessive agency, insecure tool use, data leakage, and practical Laravel middleware and validation examples to secure your AI-powered features.
Securing Laravel Queues and Background Jobs
Your queue runs code with no user watching, often with elevated access, on payloads sitting in plaintext. Here is how to encrypt sensitive jobs, lock down the backend, validate user input inside handle(), and keep failed_jobs from leaking your secrets.
ISO 27001 for Laravel Applications: Controls, Annex A, and What Developers Must Implement
ISO 27001:2022 defines 93 Annex A controls across four domains. This guide maps the technological controls that directly affect Laravel developers to specific implementations: access control, authentication, logging, cryptography, secure development, and continuous monitoring.
Monitor Your Laravel Application's Security
StackShield continuously checks your Laravel application from the outside, catching security issues before attackers find them.
Start Free Trial