Map Assets, Threats, Attack Surfaces
Learn to map assets, threats, and attack surfaces in security foundations — a practical guide for developers.
Focus: map assets, threats, and attack surfaces
Every developer has felt it: a vague sense that their application might be vulnerable, but no clear way to pinpoint where the real risks live. You can't secure what you can't see, and the first step toward a resilient system isn't writing clever defenses — it's mapping assets, threats, and attack surfaces. Without this map, you're applying security patches blindly, hoping you covered the important parts. This lesson gives you a practical, repeatable framework to see your system from an attacker's perspective, so you can prioritize defenses where they matter most.
The Problem This Lesson Solves
Modern applications are sprawling. A single feature might touch a database, a message queue, a third-party API, and a browser client — each with its own entry points and failure modes. When a security incident happens, developers often scramble to figure out what was exposed, how the attacker got in, and what they should have protected first. The pain is real: you can't enumerate every possible vulnerability, but you can systematically identify your assets, the threats against them, and the surfaces an attacker can touch.
Without a map, you're vulnerable to:
- Reactive fixes: You only patch what's already been exploited, not what could be.
- Wasted effort: You spend hours hardening a low-risk component while a critical asset sits unprotected.
- Blind spots: You assume a part of the system is safe because you never thought about it — but attackers do.
Mapping assets, threats, and attack surfaces is the security equivalent of reading the terrain before battle. It turns vague anxiety into a concrete, prioritized list of what to protect and how.
Core Concept / Mental Model
Think of your application as a castle. The castle walls are your defenses (firewalls, authentication, encryption). Inside the castle are your assets — treasures, plans, and people. The vulnerabilities are gates, windows, and tunnels — the attack surfaces through which an intruder can enter. And the threats are the besiegers: human attackers, automated malware, internal spies.
To protect the castle, you first need to know:
- Assets: What's valuable? (Data, code, credentials, uptime, user trust)
- Threats: Who or what wants to harm you? (Hackers, malicious insiders, natural disasters)
- Attack surfaces: Where can they get in? (Network ports, API endpoints, user input, physical access)
This mental model transforms abstract security jargon into a tangible inventory. You map assets to understand what to protect, threats to understand why they'd attack, and attack surfaces to understand where to defend.
In more formal terms:
- Asset: Anything with value to the organization — databases, source code, authentication tokens, customer PII.
- Threat: Any potential cause of a security incident — a hacker attempting a login attack, a disgruntled employee, a malicious script.
- Attack surface: The sum of all points where an unauthorized user can try to enter or extract data — an open port, an API endpoint, a file upload form.
How It Works Step by Step
The mapping process is iterative and practical. You don't need a huge team — a single developer can do it for a side project. The key is to be systematic and thorough.
Step 1: Inventory Your Assets
Start by listing everything that holds value. Don't overthink — write down what you know. Use a simple spreadsheet or a markdown checklist.
- Data: User records, payment info, API keys, logs
- Code: Proprietary algorithms, secrets in config files
- Infrastructure: Servers, containers, cloud storage
- People: Admin accounts, user accounts
Step 2: Identify Threats
For each asset, ask: What could happen to it? Common threat categories include:
- External attackers: Hackers seeking financial gain or notoriety
- Malware: Viruses, ransomware, cryptominers
- Insider threats: Employees misusing access (intentionally or accidentally)
Use a threat model like STRIDE (Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege) to generate threats systematically.
Step 3: Map Attack Surfaces
For each asset and threat, identify the entry points:
- Network: Open ports, public IPs, TLS misconfigurations
- Application: API endpoints, web forms, file uploads
- Human: Social engineering targeting employees
- Physical: Unlocked server rooms (less common for modern cloud apps but still possible)
Create a matrix: asset -> threat -> attack surface. This becomes your security map.
Step 4: Prioritize with Risk Ratings
Not all assets are equal. A database of customer PII is riskier than a public marketing page. Assign a rough rating (High/Medium/Low) for likelihood and impact. This gives you a starting point for where to focus security investments.
Hands-On Walkthrough
Let's apply this to a real scenario: a small REST API for a task-management app. The stack is Python with Flask and a SQLite database. We'll walk through mapping assets, threats, and attack surfaces, and then write a script to inventory the exposed attack surface!
Environment Setup
First, make sure you have Python 3.10+ and pip. Create a virtual environment and install Flask:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install flask
The Example API
Here's a simple Flask app with a couple of endpoints, an authentication token, and a database. We'll keep it deliberately naive to make the exercise concrete.
# app.py
from flask import Flask, jsonify, request
import sqlite3
app = Flask(__name__)
TOKEN = "super-secret-token"
def get_db():
conn = sqlite3.connect('tasks.db')
return conn
@app.route('/api/tasks', methods=['GET'])
def get_tasks():
token = request.headers.get('Authorization')
if token != f"Bearer {TOKEN}":
return jsonify({"error": "Unauthorized"}), 401
conn = get_db()
tasks = conn.execute("SELECT * FROM tasks").fetchall()
conn.close()
return jsonify(tasks)
@app.route('/api/tasks', methods=['POST'])
def create_task():
token = request.headers.get('Authorization')
if token != f"Bearer {TOKEN}":
return jsonify({"error": "Unauthorized"}), 401
data = request.get_json()
# No input validation or parameterized query!
conn = get_db()
conn.execute(f"INSERT INTO tasks (title) VALUES ('{data['title']}')")
conn.commit()
conn.close()
return jsonify({"status": "created"}), 201
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Note: This code is intentionally vulnerable for learning — never use it in production!
Create an Asset Inventory Script
Now let's write a Python script that parses the app source to generate a mapping. We'll scan for routes, database references, and hardcoded secrets to demonstrate the mapping process.
# map_security.py
import re
import ast
from pathlib import Path
class AssetMapper:
def __init__(self, source_file):
self.source = Path(source_file).read_text()
self.tree = ast.parse(self.source)
def find_routes(self):
"""Extract URL endpoints from Flask decorators."""
routes = []
for node in ast.walk(self.tree):
if isinstance(node, ast.FunctionDef):
for dec in node.decorator_list:
if isinstance(dec, ast.Call) and getattr(dec.func, 'attr', '') == 'route':
# Get the URL string
if dec.args:
url = dec.args[0].value
methods = [m.value for m in dec.keywords if m.arg == 'methods'][0].elts if any(k.arg == 'methods' for k in dec.keywords) else ['GET']
routes.append((url, methods))
return routes
def find_database_refs(self):
"""Find assets like database connections."""
refs = []
for node in ast.walk(self.tree):
if isinstance(node, ast.Call) and getattr(node.func, 'attr', '') in ['connect', 'execute']:
# crude approximation
refs.append((node.lineno, ast.dump(node.func)))
return refs
def find_hardcoded_secrets(self):
"""Find potential secrets like 'TOKEN ='."""
secrets = []
for node in ast.walk(self.tree):
if isinstance(node, ast.Assign):
for target in node.targets:
if isinstance(target, ast.Name) and 'TOKEN' in target.id:
secrets.append(target.id)
return secrets
if __name__ == '__main__':
mapper = AssetMapper('app.py')
print("Attack surfaces (API endpoints):")
for url, methods in mapper.find_routes():
print(f" - {methods} {url}")
print("\nAssets (database references):")
for line, func in mapper.find_database_refs():
print(f" - Line {line}: {func}")
print("\nPotential secrets:")
for sec in mapper.find_hardcoded_secrets():
print(f" - {sec}")
Now run it:
python map_security.py
Expected output (indicative):
Attack surfaces (API endpoints):
- ['GET'] /api/tasks
- ['GET', 'POST'] /api/tasks
Assets (database references):
- Line 13: Attribute(value=Name(id='conn'), attr='execute')
- Line 22: Attribute(value=Name(id='conn'), attr='execute')
Potential secrets:
- TOKEN
This script isn't a full security scanner, but it demonstrates how you can start building your own asset and attack-surface inventory from code. In a real project, you'd expand this to include dependencies, third-party calls, and infrastructure configs.
Compare Options / When to Choose What
Mapping can be done at different levels of formality. Here's a comparison of common approaches:
| Approach | Pros | Cons | Best for |
|---|---|---|---|
| Manual checklist in a spreadsheet | Fast, no tools needed, flexible | Can get outdated, no automation | Small projects, early-stage startups |
| Automated discovery scripts (like our example) | Reproducible, can be updated | Only covers what you program against | Mid-size codebases, CI integration |
| Threat modeling tools (e.g., OWASP Threat Dragon, Microsoft TMT) | Structured, built-in threat libraries | Overhead for tiny projects | Enterprise, regulated applications |
| Third-party scanners (e.g., Nmap, OWASP ZAP) | Comprehensive network coverage | Requires configuration, may miss business logic | Network-level security, penetration testing |
You don't need to pick one exclusively — many teams use a combination. The essential outcome is a living document you revisit when you add features or dependencies.
Troubleshooting & Edge Cases
My asset list feels incomplete
Start with what you know, then expand by asking: What data do you store? What credentials are on the machine? What external services do you call? If you use a cloud provider, check their inventory dashboards — they'll show you storage buckets, databases, and IAM roles.
I mapped assets but don't know where the attack surfaces are
You're not alone. Try reviewing network exposure with netstat or cloud security groups. For web apps, look for every route in your framework. Use browser dev tools to see all requests your frontend makes — each is a potential surface.
I identified a threat but can't tell if it's realistic
Use frameworks like STRIDE or CAPEC to validate. Cross-check with known vulnerabilities in your stack. A threat without a matching attack surface is either a risk from a future change or a missing surface you haven't discovered yet.
The app uses microservices — how do I map that?
Treat each service as a separate application. Create a map for each, then analyze the inter-service boundaries — those often become attack surfaces when teams assume internal trust.
What You Learned & What's Next
Now you have a structured way to think about security at the system level. You can:
- Inventory your assets — from data to infrastructure to people.
- Define threats using frameworks like STRIDE.
- Spot attack surfaces in code, network, and human interactions.
- Prioritize risks based on likelihood and impact.
You also performed a hands-on exercise to programmatically extract attack surfaces and assets from a small Flask app.
In this track, we had an earlier lesson on threat modelling lite — this mapping integrates with it. The next lesson will likely cover how to use this mapping to design defenses, like access controls or encryption, which directly address the threats you've identified.
Remember: security is a process, not a product. Your map is never done — it evolves with your codebase. Revisit it whenever you add a feature, change a dependency, or move to a new host.
Now take your asset map and try applying it to a personal project. You'll find it transforms your approach to security from random fixes to deliberate defense.
Practice recap
Now apply this to a small project of your own. List at least 5 assets, 3 threats, and 2 attack surfaces you hadn't considered before. Then write a simple Python script to scan your codebase for routes or database references. Re-run your map after adding a new feature to see how it changes.
Common mistakes
- Skipping assets like logs or backups — an attacker can leverage them to understand your system or extract sensitive data.
- Assuming attack surfaces are only network-facing APIs — forgetting file uploads, admin dashboards, or even social engineering entry points.
- Treating the map as a one-time artifact — if you don't revisit it when you add features, it quickly becomes stale and misleading.
- Confusing threat likelihood with impact — a low-probability threat can have catastrophic consequences, so always rate both dimensions.
Variations
- Use a lightweight threat modeling tool like OWASP Threat Dragon for a structured diagram instead of a manual spreadsheet.
- Automate asset discovery with Infrastructure-as-Code parsers (e.g., scanning Terraform files or Docker Compose) to capture infrastructure assets.
- Combine network scanning tools like Nmap or OWASP ZAP with code-level mapping to cover both runtime and source-code attack surfaces.
Real-world use cases
- Discovering that a forgotten staging database has no authentication, mapping it as a high-risk asset, and moving it behind a VPN.
- Using the map to justify adding Web Application Firewall rules for an API endpoint that was identified as a critical attack surface.
- Convincing management to prioritize patching a third-party library because the mapping revealed it was reachable from a public-facing route.
Key takeaways
- Mapping assets, threats, and attack surfaces gives you a concrete inventory of what to protect and what to watch.
- Use a simple mental model like a castle: assets are treasures, threats are besiegers, and attack surfaces are gates.
- Systematic steps — inventory, identify threats, map surfaces, prioritize — make the process repeatable.
- You can automate portions of mapping with simple Python scripts that parse your code for routes, secrets, and database calls.
- Your security map is a living document; revisit it whenever your system changes.
- Choose your mapping approach based on project size, from spreadsheets to dedicated threat modeling tools.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.