Threat Modeling HowTo
TL;DR
In very, very short conclusion:
Threat modeling should and can be done at almost any point in the development process, but really you should start it early in the process. You should take some “what-could-possibly-go-wrong” or attacker mentality and apply it to your feature.
For the impatient let’s have the maybe shortest possible threat modeling guide:
- Draw a diagram of your feature and point out:
- Where does untrusted input come from?
- Where are zones of different trust levels and where are the trust boundaries between those?
- Take an attackers perspective and assume worst cases to define the threats.
- Try to order by most likely and impactful threats first.
- Document the threats and map them back to your feature. Create follow-up issues with directly responsible individuals and due dates.
Note
We recommend using the Threat Model Agent for creating Threat Models that cover our requirements and guide you through the whole process, whether it be creating a new threat model or checking if a threat model is complete and valid.What is Threat Modeling
Let’s keep it short and simple here by just taking the initial sentence from our Threat Modeling handbook page:
Threat modeling is the process of taking established or new procedures, and then assessing it for potential risks.
This is maybe the most high-level and abstract description of threat modeling, now let’s put it to some practical use. We take something, an established or new process, really this might be anything. Like our own assessment-tool, a stand-alone GitLab instance or maybe a new piece of infrastructure (internal link).
For the rest of this HowTo let’s call the thing we’re doing a threat model for a feature because for GitLab most of the threat modeling which should be done would be on features of the product or features of the infrastructure of our SaaS offering.
What a threat model does, it let’s you take apart and decompose the feature you’re looking at so that you can, in some more or less formalized way, identify and describe threats towards the feature and its components. This description so far sounds really formal and might not help you to actually come up with a threat model, just take it as a vague baseline of what (identify threats) should be achieved and let’s now see how we can get there.
The formal framework that GitLab uses is called PASTA. This guide helps apply the PASTA principals in a lightweight manner to maximize their impact when followed by any GitLab team member.
When and where to start
You might wonder: “When should I start to do some threat modeling on the feature I’m planning to implement?”. It’s really not obvious but luckily it’s never too late and never too early to create a threat model for any given feature which is currently being developed or used. Also, like everything in security, it’s more of a process than a fixed, eternal state. A threat model needs to be adopted and refined if the feature changes or even if the feature stays the same but it’s being used in a different context or environment. So yes, this is some kind of “extra” work in a sense that a proper threat model just doesn’t create itself. But those extra steps will pay off soon enough by yielding more insights about the “what could possibly go wrong” moments which are also known as threats. Even tough it’s never too late it will pay off even more if you start the process early and keep the threat model up to date for any additions and changes to the feature. This is also due to the fact that the fixing of insecure design decisions might be rather complex and even disruptive(internal link).
Tools: π¨andπ§
Most threat modeling frameworks rely on some diagrams to be drawn and there’s a lot of quite heavy tooling around this. Such tools would take some data flow diagram (DFD) and automatically map certain threats to certain components based on what they are. This can be really useful in some cases, but at GitLab we need some more flexibility as the features we’re looking at often would not really fit well into the strict schematics of e.g. STRIDE based threat modeling and thus the output might not yield much meaningful threats.
Drawing diagrams
For diagrams there are almost endless possibilities, for easy and integrated usage within GitLab it’d be recommended to use one of our supported diagram tools. But really to keep it flexible and accurate you can use whatever diagramming tool you’re comfortable with. It should just deliver an accurate diagram of the feature. For instance this mermaid diagram of our Kubernetes Agent is completely sufficient as a start. It shows all involved components in their interaction at a level which is still understandable and meaningful.
graph TB agentk -- gRPC bidirectional streaming --> nginx subgraph "GitLab" nginx -- proxy pass port 5005 --> kas kas[kas] GitLabRoR[GitLab RoR] -- gRPC --> kas kas -- gRPC --> Gitaly[Gitaly] kas -- REST API --> GitLabRoR end subgraph "Kubernetes cluster" agentk[agentk] end
If we’d keep it too simple like:
graph TB agentk -- talks to --> GitLab subgraph "Kubernetes cluster" agentk[agentk] end
It’d still not be wrong but we wouldn’t be able to deduce too many detailed threats from this.
Trust and boundaries
One notable component which typically does not come with your typical architecture diagram is a trust boundary. A trust boundary is also not depicted explicitly in the Kubernetes Agent diagram, but we can deduce it. A trust boundary is separating parts in the diagram which have different levels of trust. In the Kubernetes Agent case we can see this clearly, the Kubernetes cluster can be anywhere and be controlled by anyone, it’s not really trustworthy. The GitLab controlled components however are controlled by GitLab, therefore very much trusted. So in conclusion we have a trust boundary between those two parts of the diagram. This now is the part where the actual threats come into play. The threats typically manifest at those trust boundaries. A first threat which might come to mind when just looking at this trust boundary:
- The communication between
agentkandkasmight be unencrypted
This is a very simple and generic thing to consider, still a legit concern and a first step for a threat model.
Finding the threats
For covering more of the threat ground we need to shift a bit the perspective towards a “worst-case” or “what could possibly go wrong” attitude, this generally helps a lot to find more threat scenarios. In the very formalized STRIDE approach the actual threat classes are:
Spoofing- Impersonating something or someone else
Tampering- Modifying data or code
Repudiation- Claiming to have not performed an action
Information disclosure- Exposing information to someone not authorized to see it
Denial of Service- Deny or degrade service to users
Elevation of Privilege- Gain capabilities without proper authorization
Hence the name STRIDE. While we do not use the formal STRIDE framework, we can use these threat classes to get an idea on what should be considered to define the concrete threats in our model.
So spoofing in the Kubernetes Agent example might manifest in one agentk being able to impersonate another. The example from above “The communication between agentk and kas might be unencrypted” would for instance fit in the information disclosure threat class. It’s not a matter of thinking about every possible single thing which might go wrong here. One could easily come up with an overwhelming amount of potential and rather obscure threats, but that might be very distracting and we would miss the point of the threat model. We primarily want to aim for those threats which seem likely to occur and those which are really impactful when they occur.
Consider both .com and self-managed
Make sure to think a bit out of the box: a certain feature might work well on GitLab.com but cause trouble and outages in some self-managed environment which is set up quite differently than our SaaS platform. This can be a threat as well and it’s caused due to some environmental change for our feature. This in conclusion means that we should always consider the environment our feature is being used in. That environment might change over time or in different deployment scenarios, and it might not always be friendly and trusted in the first place.
Consider Abuse and Platform Misuse
Features or products that introduce or expand access to free resources β compute minutes, storage, trial extensions, rate limit increases, or any form of quota allocation β carry an inherent abuse surface. Bad actors actively probe for ways to acquire resources at scale without paying. When the feature being reviewed touches any of the following, consider whether it could be abused for resource acquisition, cost avoidance, or platform manipulation:
- Free tier limits or trial eligibility logic
- CI/CD pipeline resources (compute minutes, runners, parallel jobs)
- DAP feature flows that could allow AI token or LLM quota abuse (e.g. proxying or redirecting allocated inference credits to third-party or unintended LLM usage)
- Invitation or referral mechanisms with resource side-effects such as CI minutes, project/namespace creations or DAP credits/trials
If you identify potential for abuse in any of these areas, loop in the Trust and Safety team early. Reach out via #abuse on Slack or tag @gitlab-com/gl-security/security-operations/trust-and-safety in your issue or MR. They can assess the abuse risk, work on detection signals, and coordinate a post-launch plan if required.
Consider Detection Measures
Signals Engineering is responsible for building threat detections to identify attempted or successful exploitation of GitLab environments - including GitLab SaaS platforms, cloud environments, and corporate systems and applications. If there are cyber threat risks identified during threat modeling exercises, coordinating findings with Signals Engineering can help mitigate known risks through proactive threat detections built by the Signals Engineering team.
Particular risks worth reaching out to Signals Engineering about include:
- Fundamental changes to major infrastructure or features for GitLab.com
- A new class of features/functionality within GitLab (such as Duo Agent Platform)
- A new GitLab feature running on a new infrastructure stack/technology
- New GitLab features introducing external integrations/attack surfaces
If you identify risks worth reaching out to Signals Engineering about, reach out via internal Slack (#security_help and tag @signals_engineering), or submit a new detection backlog issue (internal link).
What’s next?
Once the initial steps have been done and we have a first set of well thought out threats we can now use this list during development of our feature to mitigate what we’ve deemed to be the threats and worst case scenarios.
Documenting the Threat Model
The threat model will be added to the AppSec Threat Models repository(internal link). This also includes templates for threat modeling that anyone can use in issues or epics.
Ensure Ownership of Threats
Consider creating an issue with a living description which summarises the threat model each time its updated, and links off to issues for each threat, like so:
| Threat | Comments | Test / Issue |
|---|---|---|
Unencrypted communication between agentk and kas |
β grpc communication is done over TLS encrypted Websockets (see #123) | |
agentk might be able to impersonate another cluster’s agentk |
Issue #124 to review authorization | |
Attacks on gitaly level |
agentk has indirect access to gitaly via kas, this might be abused for injections or IDOR attacks |
Issue #125 - check data flows from agentk towards gitaly |
Each threat should have an Issue created where a proposal to avoid, prevent, detect, or recover from the threat is discussed by the team. These issues should have an Assignee and a Milestone or Due Date. Initially the Assignee should be the Project Manager, who will prioritise and re-assign the issue as appropriate. The Application Security engineer’s role is to help create that proposal, to help the team understand and address the issue, and to review how the threat is mitigated pre-merge.
Also remember to consider making these issues public if they are not describing a currently implemented risk; issues that discuss how to improve upon the security posture of an implementation can be made public by default.
Iterating
A threat model is never really done. The team should be familiar with the threat model and request another App Sec Review or an update to the threat model when new features or changes arise. The Application Security engineer should work closely with the team to also identify when a new threat model is needed.
Do It Yourself
Much of the language in this guide describes how Application Security engineers should threat model with teams, but that doesn’t have to be the case! Security is everyone’s responsibility and you can threat model too! Reach out to #security_help on Slack if you need help.
Threat Model Agent
Purpose
The Threat Model Agent is an AI-powered Application Security assistant that helps GitLab team members create, review, and improve threat models by themselves. It applies an Evidence-Driven PASTA framework with STRIDE classification and a 22-point compliance checklist, and supports three workflows:
- Create a new threat model from scratch
- Review and enrich an existing threat model
- Verify an existing threat model for approval
Finalized threat models are stored in the threat-models repository.
Why use the Threat Model Agent?
While an LLM-based agent can be a valuable asset for creating or evaluating threat models, it should be regarded as an enabler and support tool for the threat modeling process rather than a replacement for human judgment. Threats can be notoriously difficult to identify through automated means alone, but this approach ensures that team members never have to start from scratch. It also guarantees that threat models consistently meet our documentation requirements and maintain a uniform standard across the organization. Moreover, it delivers rapid initial results that can be iteratively refined over time. That said, the agent’s output should always be reviewed and verified by the team. We strongly encourage adding any additional threats that the agent may not have identified.Availability
The agent is currently only enabled inside the threat-models repository. This is an intentional design decision during the initial rollout. Access from other GitLab projects is planned for the future.
Starting a Session
Start the conversation by choosing the Threat Model Agent in the threat-models repository and by describing your goal, for example:
- “I want to create a new threat model for feature X.”
- “Please review this existing threat model: "
You can also ask conceptual questions first (e.g., “What does requirement D5b mean?”) without committing to a full session. If anything about the process, requirements, or terminology is unclear, ask the agent directly. It can explain individual requirements, severity classification as estimated by the agent, STRIDE categories, or how to scope a feature.
Creating a Threat Model from Scratch
Tell the agent you want to create a new threat model. It guides you through a structured discovery dialogue, asks for context about the feature, and produces a draft document with a Mermaid Data Flow Diagram, threat table, and data classification. You confirm each threat before it is included.
Working on an Existing Threat Model
Share the threat model as text, a link, or a file, and tell the agent whether you want a verification or compliance check. The agent flags weak or duplicated threats, suggests missing ones, and returns a coverage score with prioritized improvements.
Verifying and Reviewing
After drafting or enriching, the agent enters a collaborative refinement loop so you can remove false positives, challenge assumptions, or add context before anything is finalized. All refinements happen in the same conversation.
Storage Location: Always Verify
The agent automatically decides where the threat model file is stored in the threat-models repository, based on the project’s namespace and feature type. The choice is usually correct, but always double-check the file path in the final Draft MR. If the location is wrong, tell the agent where it should go and it will move the file on the same branch.
Pausing and Resuming with Draft MRs
You can interrupt the process at any point and continue later, if the chat session is still active or a (Draft) MR is created to stash your work on a threat model. MRs are always created in Draft mode and only after you explicitly confirm.
The pause-and-resume workflow:
- Pause mid-session: Stop the conversation whenever needed. Partial answers and confirmed threats are not lost as long as the chat session remains open.
- Stash work as a Draft MR: Once you have enough content to save, ask the agent to create a Draft MR in the threat-models repository. The agent detects the project’s default branch, stores the document at the correct namespace-mirrored path, links the originating issue, and appends a session metrics block to the MR description. Verify the chosen path before merging.
- Resume later: Open a new chat with the agent and share the Draft MR link. The agent picks up from the existing document, treating it as input for further verification or refinement.
- Iterate on the same branch: When you make further changes, the agent amends or adds commits to the same branch rather than creating new branches or closing/reopening MRs. This keeps the review history clean.
- Finalize: When the document is complete, assign the MR to the threat model author, remove the Draft status, and request AppSec review.
Draft MRs act as durable storage for in-progress threat models, so you can return to them as the feature design evolves.
90d33db6)
