Threat modeling Handbook #3: The Thought process behind identifying threats (with an Example)

Mohamed AboElKheir
AppSec Untangled
Published in
25 min readSep 19, 2023

Okay, It is time to jump into an actual threat modeling example. But first, let’s start with a quick recap of what was discussed in the previous 2 stories of this series (Here are the links for story 1 and story 2).

In the previous stories, we mentioned that threat modeling aims to answer the question “what could go wrong” for a specific service or feature and what can we do about it, and we mentioned that threat modeling works best if embedded in the SDLC process and we mentioned the 3 main phases of threat modeling:

  • Phase 1: Identification of high-level risks, threats, and their corresponding mitigations. It is more efficient for this phase to be performed during the design phase.
  • Phase 2: Verification of the mitigations. This should be done in the testing phase.
  • Phase 3: Continuous testing of the mitigations. The tests should be created before or shortly after the launch and should be tracked as part of the operations (e.g. embedded in the CI/CD pipeline, or running periodically and generating alerts if an issue is detected).
Threat modeling phases

In this story we start with our first example and cover phase 1 of threat modeling, as mentioned above our goal is to identify the high-level risk, the threats, and their corresponding mitigations.

Note that as we go through the example my goal is not to give a fixed methodology to identify threats, as in my opinion, the methodology needs to be flexible and able to adapt to the type of project being threat modeled and also to the experience of the people involved in threat modeling (as discussed in story 1). Instead, I will try to share my thought process as I go through threat modeling in the form of tips.

My recommendation is for you to find your own methodology by testing different things and seeing what works best for you. Remember that threat modeling is a skill that is acquired through practice, the more threat modeling you do the better you will get.

Tip#1: The best way to learn threat modeling, is to start threat modeling. Just choose any project (even an open-source one) and start creating a threat model.

Our Example: A file sharing website

Let’s assume we want to identify the threats for a file hosting and sharing website. We need to start with gathering the scope information. We setup a meeting with the development team to discuss the scope and we got the answers below (Remember the list of questions we mentioned at the end of story 2).

  • What is the problem we are trying to solve: A website that allows users to upload files, list them, download them, and/or share them with other users.
  • Who are we building this service/feature for: External public users.
  • What kind of data is being handled/stored: Customer data that can potentially be sensitive.
  • Scope Items: For this we are building:

1. A Backend REST API, let’s say using Python Django Framework and MySQL Database with the below endpoints:

/api/upload → For uploading files
/api/download → For downloading files
/api/list → For listing files
/api/share → For Sharing files
/api/unshare → For Unsharing a file
/api/delete → For deleting a file

2. A website that is a single page application using React. Let’s assume the website has one page that lists all files a user has uploaded, and files shared with the user, and has a button to upload new files, and each file has buttons to Download, Share, Unshare and Delete which use the REST API for all of these actions. Not the prettiest design, but works for our purposes.

The website

NOTE: To simplify things a bit let’s assume that user registration, login, and payment are handled by a different service which is outside of our scope, and our website can use this service in the background.

  • Design document: Let’s assume we are using AWS to host our website as shown below.
Design diagram

1. The website assets (Javascript/CSS/Images) are hosted on a public S3 bucket, and the website DNS name points to the bucket’s domain.

2. The REST API is accessible through an Application load balancer forwarding requests to multiple EC2 instances where our application is deployed.

3. RDS is used to host the MySQL database.

4. The service that handles registration, sign in, and payment (outside of our scope) keeps the tokens in the same DB our application uses, and for each token, the user name, email, and the expiry of the token are stored. Our application can use this to perform authentication, and if authentication fails it is only expected to redirect the request to the /signin page.

5. The customer Files are kept in another separate private s3 bucket. The way upload/download requests work is that the application generates an S3 pre-signed URL and returns it in the response of the request, then within the browser, the React application uses this pre-signed URL to upload/download.

Swim lane diagram for upload/download
  • Data being handled:
  1. Customer data that is potentially sensitive (contents of the uploaded files). This is stored in the private s3 bucket.
  2. Customer PII such as emails are used for sharing/unsharing. This is stored in the DB.
  3. Other metadata such as the s3 location of an uploaded file. This is stored in the DB.
  • Credentials being handled:
  1. The session tokens used for authentication.
  2. The pre-signed URLs used to download/upload files to s3 should be treated as credentials as they allow access to customer data.
  3. The AWS credentials used by EC2 instances to call the s3 service to create the pre-signed URLs. Let’s assume we are using an instance profile role.
  4. The DB credentials used by the EC2 instances to call the RDS MySQL database.

Tip#2: Make sure you fully understand how the service works before jumping into threat identification as any false assumptions could lead to misses. Ask the development team all the questions you may have (especially the stupid ones), read the documentation for any technologies you are not familiar with, try the service in a testing environment, .. etc.

High-level Risks: The News Headlines

Now it is time to take off the “How it works” hat and wear the “What could go wrong” hat. While some people jump directly to identifying the threats I prefer starting with the High-level risks.

NOTE: While the words risk and threat can be used interchangeably to mean the same thing, in this context we use the word risk to describe the undesired outcome (e.g. customer data getting exposed), and the word threat to describe the actual technique or misconfiguration that leads to the undesired outcome (e.g. An attacker can use SQL injection to expose other customers’ data). Think about it this way, if your service actually is affected by a breach, the risk would be on the headline of the news, and the threat would be mentioned in the details of the report.

The reason I prefer starting with the risks is that this helps define the goal and the scope of the threat model, and increases the likelihood of the threats identified being relevant to this scope. Otherwise, you could easily get side-tracked by some technically interesting but low-impact, low-likelihood, or irrelevant threats. Also, besides security risks, there are other types of risks like availability and resilience risks which you may or may not want to include in the threat modeling discussion, hence, agreeing on this early own through explicitly stating the risks from the beginning makes it easier to decide which threats are relevant.

One of the best tools for identifying high-level risks is the STRIDE model. STRIDE is a mnemonic for six main categories of security risks:

  • Spoofing: Violating Authentication (being able to claim you are someone else).
  • Tampering: Violating Integrity.
  • Repudiation: Not being able to prove actions were performed by who actually performed them.
  • Information Disclosure: Violating Confidentiality.
  • Denial of Service: Violating Availability.
  • Elevation of Privilege: Violating Authorization (being able to perform actions your user shouldn’t be allowed to perform).

The other thing we need is to define the main assets we want to protect which is usually either some form of sensitive data (e.g. customer or internal confidential data) or actions performed on behalf of our customers (e.g. agreeing to an agreement). In our case, there were 2 main assets mentioned above:

  • Customer data that is potentially sensitive (contents of the uploaded files).
  • Customer PII such as emails are used for sharing/unsharing.

From the above, we can identify the below high-level threats:

  1. Exposure of the customer file data.
  2. Tampering with the customer file data.
  3. Exposure of customer PII.
  4. Denial of service.
  5. Not having an audit trail showing which customers perform which actions (e.g. upload, download, sharing, .. etc), and when.

NOTE: We didn’t include authentication and authorization bypasses in the high-level risks as the main impact of these would be data exposure or tampering. However, this is just my opinion, you can always add them as separate risks if you prefer.

Keep in mind that there are other risks you may want to consider that don’t fully fit under STRIDE, e.g. For our example there is a risk that someone uses our website to upload malware and use it for phishing victims that are not our direct customers, which could impact our company’s reputation even if it doesn’t directly impact our company or its direct customers. That being said, STRIDE is always a good place to start for identifying high-level risks.

Tip#3: Apply STRIDE to your assets (e.g. customer data and actions performed on behalf of the customer) to find the list of high-level risks. This helps you define the scope of the threat model discussion and identify relevant threats in the next step.

High-level Risks identified

Identifying the Threats: Into the Rabbit Hole

Now that we have identified the main high-level risk in our scope, it's time to get one more step deeper and identify the different threats that could lead to these risks.

Let’s start with the first 2 risks related to customer file data:

  1. Exposure of the customer file data.
  2. Tampering with the customer file data.

To identify the related threats the first question we need to answer is where in our setup the data we want to protect can be found, now is a good time to use our design diagram. As we are using pre-signed URLs from the browser to upload/download, the data will be in 3 main places:

  • The private S3 bucket.
  • The browser.
  • In transit between the bucket and the browser.
Places that have customer file data

Let’s take these places one by one and try to identify what could go wrong.

  • The private S3 bucket: If we are not familiar with things that could go wrong with S3 buckets we can check the S3 public documentation which has a security best practices page. From this, we can find the below 2 threats and their mitigations.

Threat#1: An attacker with access to AWS credentials that can read from/write to the s3 bucket can expose/tamper with customer data by directly accessing the bucket.
Mitigation 1: Access to the AWS account containing the bucket uses two-factor authentication and only the development team is authorized.
Mitigation 2: Bucket is not set to public.

Threat#2: An attacker with access to the physical storage where the S3 objects are stored can read/tamper with customer data.
Mitigation: Encryption at rest by default is enabled on the s3 bucket.

  • The browser: There are many web attacks that affect browsers, OWASP Top 10 is one of the best resources to check here to identify the threats. With that in mind, we can find one obvious threat which is XSS, and we can follow OWASP’s prevention guide to decide on the mitigations.

Threat#3: An attacker can use an XSS vulnerability in the web application to steal the session cookie or the pre-signed url used to upload/download the data, allowing the attacker to read/write customer data.
Mitigation 1: We are using React which performs html encoding by default which mitigates XSS unless a function like dangerouslySetInnerHTML is used.
Mitigation 2: We will implement a CSP header that doesn’t allow unsafe-inline or unsafe-eval for script-src. This tells the browser never to allow inline JS which is typically needed for XSS.
Mitigation 3: We are using the httpOnly Cookie flag on the session cookie which doesn’t allow JS (and by extension XSS) to access the cookie value.

  • In transit between the bucket and the browser: We can easily mitigate all the threats related to data exposure and tampering and also ensure the authenticity of the S3 endpoint used for file download/upload by simply using TLS.

Threat#4: An attacker with access to the network between the user’s browser and the S3 endpoint can read/write customer data.
Mitigation 1: TLS is used for calling the S3 endpoint.
Mitigation 2: As per the S3 security best practices page, we can add the aws:SecureTransport condition to the bucket policy to ONLY allow TLS connections.

Tip#4: To identify the threats relevant to a components you need to understand this component and what usually goes wrong with it, and one good way to do this to read its documentation especially the security best practices section. If you can’t find it, use Google or ChatGPT. Besides security best practices, searching for related bug bounty reports and vulnerability write-ups could be useful.

Identifying the Threats: Check the Indirect paths

Okay, so we have identified 4 threats by following the data directly, that is good, but not good enough, and there are other in-direct ways the customer data can be exposed and tampered with. For example:

  • If the attacker is able to trick the user into calling the Sharing action and sharing it with the attacker’s user.
  • If the attacker is able to bypass authorization and directly call the REST API to download, share, or upload files.
  • If the attacker is able to access the pre-signed URL itself or the session token of the user.
  • If the attacker is able to access another component that has permission to generate the pre-signed URL, e.g. the EC2 instance.

Tip#5: When identifying the threats related to data exposure/tampering following the data is a good start, but also think about the other indirect ways and bypasses that could lead to data access (e.g. exposure of a credential that gives access to data).

Let’s take these indirect ways one by one:

  • If the attacker is able to trick the user into calling the Sharing action and sharing it with the attacker’s user.

Regarding tricking the user into calling the Sharing action, there is a way to do that from the browser which is CSRF. If the attacker can send a link that calls the /api/share endpoint to the user via email, another malicious website, or using another vulnerability, the link could use the session token in the user's browser and share the file without the user noticing. To protect against that we can check OWASP’s CSRF prevention guide, and as we are using Django we can also check Django’s public documentation’s recommendation.

Threat#5: An attacker can use CSRF to trick the user to share a file with the attacker’s user.
Mitigation 1: We will use Django’s CSRF middleware for all mutating actions of the REST API.
Mitigation 2: As per OWASP’s recommendations we will use the SameSite cooke flag on the session cookie used to call the REST API.

  • If the attacker is able to bypass authorization and directly call the REST API to download, share, or upload files. This generates the below threat:

Threat#6: An attacker can bypass authorization of the REST API to be able to read/write/share customer data.
Mitigation 1: All REST API actions expect the session token to be passed as a header, and validates it. If it is missing or invalid the request is re-directed to the /signing page.
Mitigation 2: All REST API actions will verify the file is either owned by or shared with the authenticated user.

  • If the attacker is able to access the pre-signed URL itself or the session token of the user. Let’s have another look at the design diagram to identify the places where the session cookie and the pre-signed URLs can be found.
Places that have pre-singed URLs and session tokens.

Similar to what we have done before we have identified 6 places, the browser, in transit between the browser and the ALB, in transit between ALB and the Application Servers, on the Application Servers, and in transit between the Application servers and The DB. We have already discussed the first one (the browser), so we can start with the second (in transit between the browser and the ALB):

Threat#7: An attacker with man-in-the middle access between the customer and the REST API endpoint (ALB) can read the session cookies or pre-signed URLs sent in the request.
Mitigation 1: The REST API endpoint uses TLS with a valid certificate managed by AWS Certificate Manager.
Mitigation 2: The REST API will use the HSTS header with pre-load. This tells the browser to never use plain text HTTP for this domain.

Similarly for in-transit between ALB and the Application Servers, and between the Application Servers and the DB.

Threat#8: An attacker with man-in-the middle access between the REST API endpoint (ALB) and the Application Servers can read the session cookies or pre-signed URLs sent in the request.
Mitigation: The service running on the Application Server uses TLS.

Threat#9: An attacker with man-in-the middle access between the Application Servers and the DB can read the session cookies sent in the request.
Mitigation: The DB is configured to require_secure_transport so that TLS is used for the connection.

NOTE: Note that while threats 7, 8, and 9 look very similar, threat 7 is much more likely and important to mitigate, as typically the communication between the ALB and the EC2 instance and between the EC2 instances and RDS in the same VPC would be within the AWS network which means an attacker having access to this network path is much less likely. This is why it could be more efficient to decide on the assumptions and the possible entry points (what an attacker has access to) before starting threat modeling so that low-likelihood or unimportant threats are ignored. However, for this exercise, our goal is just to show the thought process so we have decided to skip this for this example.

Tip#6: Deciding on the assumptions and the possible entry-points (what an attacker has access to) before starting threat modeling helps filter out low-likelihood or unimportant threats.

Now let’s move on to the Application Servers. Now is a good time to remember that the boxes in the design diagram are abstractions hiding other things not shown in the design diagram. For example, the diagram shows that the Application Servers are EC2 instances that have the service running on them, but the diagram doesn’t show:

  • What OS version is running on the instance?
  • What packages are installed on the instances?
  • What services are running on the instances?
  • Which of these services are listening on remote ports?
  • Which of these services allow remote access (e.g. SSH or RDP)?
  • What are the network firewall rules/security group rules applied on the instance?
  • What libraries and packages are used by the Django application?
  • Are any of the sensitive parameters (session token or pre-signed URLs) written to the disk (e.g. to local log files)?
  • Are we writing log files remotely (e.g. to a service like CloudWatch)?
  • Are there any credentials stored on the instances (e.g. instance profile role credentials)?
Breaking down the Application Server abstraction

All of these things not shown on the design diagram could have vulnerabilities or misconfigurations leading to the exposure or tampering of customer data. When you are wearing the “How it works” hat it is mostly ok to keep the abstraction to make things easier to follow and understand, but now we have the “What could go wrong” hat on, and for that we need to breakdown the abstraction as everything included within could introduce new threats.

Tip#7: Boxes in the design diagram are usually abstractions, when threat modeling always think about what lies under this abstraction as all of these sub-components could introduce new threats.

For our example, we can identify the below threats from the list above showing different things running on the Application EC2 instances.

  • Operating system, and Installed packages:

Threat#10: A vulnerability affecting the OS or the packages installed on the Application Servers that is reachable by user input could allow an attacker to access the credentials on the instance (session cookie, pre-signed URL, instance profile role credentials, or DB credentials) leading to customer data exposure/tampering.
Mitigation 1: The OS and the packages are periodically patched and upgraded to the latest versions.
Mitigation 2: We have a vulnerability scanner (e.g. AWS Inspector) periodically running on the instances and alerting on High/Critical vulnerabilities.
Mitigation 3: All input parameters will have input validation that only allows the input matched the expected pattern (regex) constraint limiting dangerous characters usually needed for attack payloads.

  • Listening services:

Threat#11: A vulnerability affecting a service listening remotely could allow an attacker to access the credentials on the instance (session cookie, pre-signed URL, instance profile role credentials, or DB credentials) leading to customer data exposure/tampering.
Mitigation 1: Only necessary services are running
Mitigation 2: We have a security group rule that only allows remote access to the port used by the Django Application service.

  • Remote Access:

Threat#12: Remote access with no or weak authentication could allow an attacker to remotely login to the instance and access the credentials on the instance (session cookie, pre-signed URL, instance profile role credentials, or DB credentials) leading to customer data exposure/tampering.
Mitigation: All remote access is disabled OR only SSH is enabled through two-factor authentication only allowed to the team through a bastion host.

  • Application libraries:

Threat#13: A vulnerability affecting a library used by the application that is reachable by user input could allow an attacker to access the credentials on the instance (session cookie, pre-signed URL, instance profile role credentials, or DB credentials) leading to customer data exposure/tampering.
Mitigation 1: All libraries used by the application are periodically being upgraded to the latest version.
Mitigation 2: We can use an SCA tool like pip-audit within the pipeline or schedule it periodically to get notified on Critical/High severities.
Mitigation 3: All input parameters will have input validation that only allows the input matched the expected pattern (regex) constraint limiting dangerous characters usually needed for attack payloads.

  • Local disk:

Threat#14: An attacker with access to the physical storage where the EBS volumes attached to the instance are stored can access the credentials on the instance (session cookie, pre-signed URL, instance profile role credentials, or DB credentials) leading to customer data exposure/tampering.
Mitigation 1: All EBS volumes are encrypted at rest.
Mitigation 2: We don’t store the actual customer data or any of the credentials directly to the disk in configuration files or local log files.

  • Remote logs:

Threat#15: An attacker with access to the remote logs the application is writing can find in the logs customer data or credentials leading to customer data exposure/tampering.
Mitigation 1: We don’t store the actual customer data or any of the credentials to the logs.
Mitigation 2: Access to the remote logs is only accessible to the admins through two-factor authentication.

  • The Application: Note that this sub-component is in itself another abstraction for a very complex thing which is the actual code of the REST API. There are many vulnerabilities that could be introduced by the code (CWE Top 25 is a good place to start for learning about this), and finding which ones are relevant is a bit tricky as there are multiple factors.
    Some issues are only relevant to specific languages, like the issues related to memory safety generally (e.g. buffer overflows), as we are using Python which is a memory-safe language we know these are not relevant.
    For other issues, like SQL injection, Directory traversal, SSRF (Server-side request forgery), and Command injection to decide whether they are relevant we need to understand the source-sink model (Here is a very good video about this). To summarize, for each one of these attacks to work the below conditions need to be met:
    1. The Source: User input that the attacker has control over (e.g. one of the input parameters or the headers sent in the API request).
    2. The Sink: A dangerous function or call that is reachable by the input coming from the Source.
    3. Missing or insufficient input validation: The input coming from the Source is not being validated and/or properly encoded before being passed to the Sink.
    Let’s take the attacks we mentioned one by one:
    - SQL Injection: The Sink for SQL injection is an SQL query or a library performing an SQL query in the background, which is present in our application. The Source is user input, and as things we are getting from input like session tokens, file IDs, .. etc are being added to the SQL queries, then SQL injection is relevant.
    - Directory Traversal: The Sink is a directory path we are downloading/uploading a file from, and the Source is user input. In our case no user input is being used to build a directory path, so this attack is most probably NOT relevant (A code review can help verify this).
    - SSRF: The Sink is a URL we are sending a request to, and the Source is user input. Our application is calling 2 main URLs which are the S3 endpoint used to generate the pre-signed URLs and the DB URL to connect to the DB, but both are static and not manipulated by user input, so this is not relevant as well.
    - Command injection: The Sink is a command we are running, and the Source is user input. No user input is used to run a command, so this is not relevant as well.
Only include the attacks that have a possible connection between the related sources and sinks

From that we can add the below threat:

Threat#16: An attacker can use an SQL injection vulnerability to gain access to customer data or credentials used to gain access to customer data.
Mitigation 1: Django’s documentation mentions querysets are protected against SQL injection as they use Parameterization which is also what OWASP recommends on their SQL injection prevention page.
Mitigation 2: All input parameters will have input validation that only allows the input matched the expected pattern (regex) constraint limiting dangerous characters usually needed for attack payloads.

Tip#8: Know the Sources getting into the code, and the dangerous Sinks these Sources are reaching to identify the threat that could be introduced by the code.

Now time to move to the last place having credentials that could give access to customer data (session tokens) which is the DB itself. Again, remember that this is also an abstraction.

Breaking down the DB abstraction

However, note that RDS is a managed service which means some of the abstracted components are fully managed by the Cloud provider, which means that we can choose to “Transfer” the related threat to the Cloud provider, which means we don’t need to mitigate them ourselves, but expect the Cloud provider to do that for us. In that decision, we are taking a bit of risk which we can decide whether is acceptable or not based on the situation.

Tip#9: You can choose to “Transfer” some of the threats to another service, downstream dependency, Cloud provider, .. etc. Just keep in mind this is risk associated with this, and you need to decide whether the risk is within acceptable levels or not.

This leaves us with 2 threats related to the DB:

Threat#17: An attacker with access to the physical storage of the DB can read the session tokens which allow access to customer data.
Mitigation: We are enabling encryption at rest for the RDS database.

Threat#18: An attacker with access to the DB credentials can directly access the DB to read session tokens which can be used to access customer data
Mitigation 1: DB has a security group rule that only allows network connectivity from the Application Servers.
Mitigation 2: DB credentials are kept in secrets manager, and only the Application Server instance profile role is allowed to read the secret value.
Mitigation 3: The DB credentials are automatically rotated periodically.
Mitigation 4: The DB credentials are never writton on disk on the Application Servers.

Identifying the Threats: Back to the remaining High-level Risks

I think this should cover us for the first 2 high-level risks. Let’s move on to the third one:

3. Exposure of customer PII.

If you think about this one you will find that this is kind of the same as the first 2 risks, as the customer PII is in the same places the customer data and the credentials are in, hence the threats and the mitigations we have already identified already covers this risk as well.

4. Denial of service.

The main entry point for DoS attacks would be the ALB assuming the other tiers are not publicly accessible from the internet. This leaves us with 2 threats:

Threat#19: An attacker can send a high volume of unauthenticated DoS requests to crash or slow down the application.
Mitigation 1: ALB already provides protection against unauthenticated network level attacks.
Mitigation 2: Auto-scaling is enabled which makes the application more resilient to high spikes.

Threat#20: An attacker can send a high volume of authenticated DoS requests to crash or slow down the application.
Mitigation: We can apply rate-limiting per session or per user to prevent one user from affecting the other users. (e.g. django-ratelimit)

5. Not having an audit trail showing which customers perform which actions (e.g. upload, download, sharing, .. etc), and when.

Threat#21: Not having an audit trail showing which customers perform which actions (e.g. upload, download, sharing, .. etc), and when.
Mitigation 1: We have access logs enabled on the ALB, the public S3 bucket, and the private S3 bucket.
Mitigation 2: The instance, application, and DB logs are sent to CloudWatch.
Mitigation 3: We have Cloudtrail enabled to track API calls in the AWS account.

Identifying the Threats: How about the other components in the diagram?

Ok, now we have gone through all the High-level risks, but just to make sure we are not missing anything let’s have a look at the components in the design diagram we haven’t discussed yet.

Components we haven’t discussed yet

The 2 components we haven’t discussed are:

  • The Public Bucket with the Web Assets: While for this bucket anyone is allowed to read the assets stored on it, if an attacker is able to write to the bucket they can introduce malicious code to it and use it to expose/tamper with customer data.

Threat#22: An attacker can submit malicious code to the public bucket using it to expose/tamper with customer data.
Mitigation: Only our pipeline and our admins have write access to the bucket through two-factor authentication.

  • The DNS hosted Zone: Same an attacker with access to the DNS hosted zone can re-direct the domain name to their malicious website.

Threat#23: An attacker with access to the DNS hosted zone can re-direct the domain name to their own malicious website.
Mitigation: Only our admins have write access to the DNS hosted zone through two-factor authentication.

Identifying the Threats: How about the other components NOT in the diagram?

Again, remember the diagram is just an abstraction, there are other components that are not in the diagram, let’s take 3 examples:

  • The Code repo: The repo that has the code on Github/GitLab/..etc. If an attacker can submit code there, they can expose or tamper with customer data.

Threat#24: An attacker with access to the code repo can submit code there, they can expose or tamper with customer data.
Mitigation: Only our developers are allowed to read or submit commits/PRs to the Code repo through two-factor authentication.

  • The pipeline: The pipeline used to build and deploy the application.

Threat#25: An attacker with access to the pipeline can tamper with the application which can be used to expose or tamper with customer data.
Mitigation: Only our developers are allowed to access the pipeline through two-factor authentication.

  • Other services sharing the Database:

Threat#26: Other services sharing the the database could have SQL injection leading to the exposure of the fields our application is using.
Mitigation: We can have least-privilege DB permissions for all services using the DB to minimize this risk.

Tip#10: Think about how the components in the diagram as well as the other relevant components not in the diagram could lead to the high-level risks in your scope even if they are not in the direct or in-direct path of the data.

Phase 1 Complete 🎉

Conclusion

If you have reached this point, I would like to thank you for reading. I know by now you may be a bit overwhelmed with all the details, and this is completely normal especially if you don’t have prior experience in threat modeling. However, don’t worry as in the next story I will discuss in more detail how to make sense of the thought process we followed in this example, and I will give some tips on how to get better at threat modeling.

As I mentioned earlier this is my personal approach, but eventually, you will have your own different approach that works for you as you gain more experience. Until then, I will leave you with the Tips we mentioned throughout the example, as I think they give a good summary of what was discussed. Stay tuned for the next story!

Tip#1: The best way to learn threat modeling, is to start threat modeling. Just choose any project (even an open-source one) and start creating a threat model.

Tip#2: Make sure you fully understand how the service works before jumping into threat identification as any false assumptions could lead to misses. Ask the development team all the questions you may have (especially the stupid ones), read the documentation for any technologies you are not familiar with, try the service in a testing environment, .. etc.

Tip#3: Apply STRIDE to your assets (e.g. customer data and actions performed on behalf of the customer) to find the list of high-level risks. This helps you define the scope of the threat model discussion and identify relevant threats in the next step.

Tip#4: To identify the threats relevant to a components you need to understand this component and what usually goes wrong with it, and one good way to do this to read its documentation especially the security best practices section. If you can’t find it, use Google or ChatGPT. Besides security best practices, searching for related bug bounty reports and vulnerability write-ups could be useful.

Tip#5: When identifying the threats related to data exposure/tampering following the data is a good start, but also think about the other indirect ways and bypasses that could lead to data access (e.g. exposure of a credential that gives access to data).

Tip#6: Deciding on the assumptions and the possible entry-points (what an attacker has access to) before starting threat modeling helps filter out low-likelihood or unimportant threats.

Tip#7: Boxes in the design diagram are usually abstractions, when threat modeling always think about what lies under this abstraction as all of these sub-components could introduce new threats.

Tip#8: Know the Sources getting into the code, and the dangerous Sinks these Sources are reaching to identify the threat that could be introduced by the code.

Tip#9: You can choose to “Transfer” some of the threats to another service, downstream dependency, Cloud provider, .. etc. Just keep in mind this is risk associated with this, and you need to decide whether the risk is within acceptable levels or not.

Tip#10: Think about how the components in the diagram as well as the other relevant components not in the diagram could lead to the high-level risks in your scope even if they are not in the direct or in-direct path of the data.

--

--