[{"data":1,"prerenderedAt":719},["ShallowReactive",2],{"/en-us/blog/how-to-configure-dast-full-scans-for-complex-web-applications/":3,"navigation-en-us":35,"banner-en-us":464,"footer-en-us":481,"Dennis Appelt":691,"next-steps-en-us":704},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":25,"_id":28,"_type":29,"title":30,"_source":31,"_file":32,"_stem":33,"_extension":34},"/en-us/blog/how-to-configure-dast-full-scans-for-complex-web-applications","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"How to configure DAST full scans for complex web applications","Keep your DAST job within timeout limits and fine-tune job configurations for better results","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679617/Blog/Hero%20Images/tuning-237454.jpg","https://about.gitlab.com/blog/how-to-configure-dast-full-scans-for-complex-web-applications","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to configure DAST full scans for complex web applications\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Dennis Appelt\"}],\n        \"datePublished\": \"2020-08-31\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"Dennis Appelt","2020-08-31","Shifting [Dynamic Application Security\nTesting](https://docs.gitlab.com/ee/user/application_security/dast/) (DAST)\nleft can help to detect security vulnerabilities earlier in the software\ndevelopment lifecycle (SDLC). However, testing earlier and more often in the\nSDLC comes with its own set of challenges: an abundance of alerts from\nautomated security tools and a high computational cost caused by frequent\nand long-running CI security jobs.\n\n\nIn this blog post, I’ll walk you through how we configured DAST for the\ninternal pipeline that tests the GitLab web application. We’ll discuss some\nof the common challenges that you might encounter when testing large\napplications, such as: \n\n\n1. How to keep the duration of the DAST scan within an acceptable [job\ntimeout](https://docs.gitlab.com/ee/ci/pipelines/settings.html#timeout):\nThis matters because jobs that exceed timeouts will fail and no results will\nbe displayed. We will review how to optimize scan duration by excluding\nlow-risk parts of the application from being tested, by correctly seeding\nyour application with test data, and by parallelizing the DAST job.\n\n\n2. How to get relevant results for your context: This is key – tuning job\nconfigurations to produce relevant results allows your engineers to focus on\nfindings that matter and prevents [alert\nfatigue](https://en.wikipedia.org/wiki/Alarm_fatigue). In this area, we'll\ndiscuss criteria for identifing rules that are applicable to your\napplication and we will explain how to disable irrelevant rules.\n\n\nThe discussed solutions are based on the DAST configuration that we use to\ntest GitLab itself. If you are looking for inspiration on how to configure\nyour own DAST jobs, feel free to take a look at our\n[configuration](https://gitlab.com/gitlab-org/gitlab/-/blob/8b1557c02fe5519ba952ea59c93b84912dd357b4/.gitlab/ci/dast.gitlab-ci.yml).\n\n\n## How to set up a simple DAST full scan\n\n\nKicking off a DAST full scan in GitLab CI is as easy as including the job\ntemplate and setting a few variables in your `.gitlab-ci.yml` file:\n\n\n```yaml\n\ninclude:\n  - template: DAST.gitlab-ci.yml\n\nvariables:\n  DAST_WEBSITE: \"https://my-site.example\"\n  DAST_FULL_SCAN_ENABLED: \"true\"\n  DAST_AUTH_URL: \"https://my-site.example/signin\"\n  DAST_AUTH_USERNAME: “john”\n  DAST_AUTH_PASSWORD: “P@ssw0rd”\n```\n\nThe variable `DAST_WEBSITE` defines the target website tested by DAST.\nSetting `DAST_FULL_SCAN_ENABLED: true` instructs DAST to run a [full\nscan](https://www.zaproxy.org/docs/docker/full-scan/), which is more\ncomprehensive than a [baseline\nscan](https://www.zaproxy.org/docs/docker/baseline-scan/) and potentially\nfinds more vulnerabilities. There are also other config options that you\nlikely want to define such as authentication-related options (`DAST_AUTH_*`)\nwhich are not discussed here. You can check out our DAST [user\ndocs](https://docs.gitlab.com/ee/user/application_security/dast/#available-variables)\nfor a refresher on these config options.\n\n\nWhen running a DAST full scan against a web application with many pages and\ninput parameters, it is possible that the DAST job will not finish testing\nthe application within the CI job timeout and fail. If this is the case for\nyour DAST job, keep reading to learn about tweaking your job configuration\nto stay within the timeout.\n\n\n## How to optimize DAST scan duration\n\n\nIt is not uncommon that a DAST full scan can take 10 or more hours to\ncomplete testing in complex applications. To understand how we can reduce\nthe scan duration, we need to take a closer look at how DAST works\ninternally.\n\n\nDAST job execution is roughly separated into two phases: A spidering phase\nand a test execution phase. A DAST job starts with spidering, during which\nit will detect all pages a web application consists of and identify the\ninput parameters on these pages. The spider recursively discovers all pages\nof an application by visiting the configured target URL (parameter\n`DAST_WEBSITE`) and by following all URLs found in the page source. These\nURLs are in turn also searched for URLs in their page source, any new URLs\nare followed and so on. In a DAST full scan, this procedure is typically\nrepeated until all discovered URLs have been visited.\n\n\nIn the test execution phase, test rules are executed against the target\napplication to find vulnerabilities. Most of the rules are executed for any\nof the discovered pages in the spidering phase, leading to a direct relation\nbetween the number of executed test cases and the number of discovered\npages.\n\n\nSome rules check for specific CVEs such as\n[Heartbleed](https://www.zaproxy.org/docs/alerts/20015/) while others are\nonly applicable to applications written in specific languages such as\n[Java](https://www.zaproxy.org/docs/alerts/90002/),\n[ASP.net](https://www.zaproxy.org/docs/alerts/10061/), and so on. A DAST\nfull scan will, by default, execute all rules even if the target\napplication’s tech stack is not affected by the vulnerability being tested\nfor.\n\n\nTo summarize, you can use the following rule of thumb to estimate a DAST\njob’s scan duration: Number of Tested Pages **x** Number of Executed Rules. \n\n\nTo optimize scan duration, we will have to tweak these factors.\n\n\n### How to reduce the number of tested pages\n\n\nTo understand which pages of our application are tested we can refer to the\njob log. The URLs of all tested pages are listed like in the example below.\n\n\n```\n\n2020-08-01 00:25:34,454 The following 2903 URLs were scanned:\n\nGET https://gitlab-review.app\n\nGET https://gitlab-review.app/*/*.git\n\nGET https://gitlab-review.app/help\n\nGET https://gitlab.com/help/user/index.md\n\n...\n\n```\n\n\nBased on this information we can exclude low-risk pages from being tested.\nFor example, for the GitLab web app we decided to\n[exclude](https://gitlab.com/gitlab-org/gitlab/-/blob/8b1557c02fe5519ba952ea59c93b84912dd357b4/.gitlab/ci/dast.gitlab-ci.yml#L30)\nany of the [help pages](https://gitlab.com/help). These pages are mostly\nstatic and the application code doesn’t process any user-controlled inputs,\nwhich rules out attack categories like SQL injection, XSS etc. Excluding\nthese led to 899 URLs less being spidered and tested, reducing the scan\nduration significantly.\n\n\nTo exclude low-risk pages from being tested, you can use the environment\nvariable\n[DAST_AUTH_EXCLUDE_URLS](https://docs.gitlab.com/ee/user/application_security/dast/#available-variables)\nas mapped out below:\n\n\n```yaml\n\nscript:\n  - 'export DAST_AUTH_EXCLUDE_URLS=\"https://gitlab-review.app/help/.*,https://gitlab-review.app/profile/two_factor_auth\"' \n```\n\n\n`DAST_AUTH_EXCLUDE_URLS` takes a comma-separated list of URLs to exclude.\nURLs can contain regular expressions, e.g.\n`https://gitlab-review.app/help/.*` will exclude any URL that starts with\n`https://gitlab-review.app/help/`.\n\n\n### How to populate your app with test data\n\n\nPopulating your application with test data is important because it allows\nDAST to discover and test all the functionality of your application. At the\nsame time, you want to avoid adding redundant test data to your application,\nwhich would lead to DAST exercising the same code repeatedly.\n\n\nFor example, we can create multiple\n[projects](https://docs.gitlab.com/ee/user/project/) in a GitLab instance\nand each project will be accessible via a unique URL, e.g.\n`https://gitlab.example/awesome-project`,\n`https://gitlab.example/another-project`, etc. To DAST these look like\nunrelated pages and it will test each page separately. However, the\napplication code that is processing requests to different projects is\nlargely identical, leading to the same code being tested multiple times.\nThis increases the scan duration and is unlikely to identify more\nvulnerabilities than testing only a single project would.\n\n\nIn every pipeline that runs DAST against GitLab, we spin up a fresh GitLab\ninstance as a [review app](https://docs.gitlab.com/ee/ci/review_apps/) and\npopulate it with the test data that we need for the DAST job. If you are\nlooking for a similar solution, you might find the job that is [deploying\nthe review\napp](https://gitlab.com/gitlab-org/gitlab/-/blob/8b1557c02fe5519ba952ea59c93b84912dd357b4/.gitlab/ci/review.gitlab-ci.yml#L53-83)\nand seeding it with [test\ndata](https://gitlab.com/gitlab-org/gitlab/-/blob/8b1557c02fe5519ba952ea59c93b84912dd357b4/.gitlab/ci/review.gitlab-ci.yml#L83)\ninteresting.\n\n\n### Identifying relevant rules for your DAST scan\n\n\nAs mentioned above, a DAST full scan runs, by default, all rules against any\ndiscovered page. Therefore, another way to reduce scan duration is to\ndisable irrelevant rules or rules that you have determined are low-risk for\nyour application context. To determine rule relevance, consider the\nfollowing:\n\n\n- Does the rule apply to my web framework?\n\n- Does the rule apply to my web server?\n\n- Does the rule apply to my database server?\n\n- Does the type of vulnerability a rule tests for apply to my application?\n\n\nFor example, if your application is not built with Java, rules that test for\n[Java-specific vulnerabilities](https://www.zaproxy.org/docs/alerts/90002/)\ncan be disabled. There are many rules that are specific to a web framework,\nserver, or database being used like [Apache HTTP\nServer](https://www.zaproxy.org/docs/alerts/10053/),\n[ASP.NET](https://www.zaproxy.org/docs/alerts/10061/),\n[PostgreSQL](https://www.zaproxy.org/docs/alerts/40022/) etc. If in doubt\naround which rule(s) are applicable to which tech stack, you can find the\ninformation either in the [ZAP user\ndocs](https://www.zaproxy.org/docs/alerts/) or directly in the [rule\nimplementation](https://github.com/zaproxy/zap-extensions/blob/master/addOns/ascanrules/src/main/java/org/zaproxy/zap/extension/ascanrules/CodeInjectionScanRule.java#L86-L91):\n\n\n```java\n\npublic boolean targets(TechSet technologies) {\n    if (technologies.includes(Tech.ASP) || technologies.includes(Tech.PHP)) {\n        return true;\n    }\n    return false;\n}\n\n```\n\nNote: Most rules classes have a function `targets` that defines to which\ntechnologies a rule is applicable.\n\n\nAnother example of a rule that might not apply to your application is the\n[PII Disclosure](https://www.zaproxy.org/docs/alerts/10062/) rule if your\napplication does not process any PII.\n\n\n### Excluding irrelevant rules\n\n\nThe execution time of individual rules varies substantially. To understand\nhow much time a particular rule adds to the total scan duration and how much\nwe could gain from disabling it, we turn again to the job log. Each rule\nprints its duration on completion, for example:\n\n\n```\n\n[zap.out] 3937350 [Thread-8] INFO\norg.parosproxy.paros.core.scanner.HostProcess - completed host/plugin\nhttps://gitlab-review.app | TestExternalRedirect in 2813.043s with 33151\nmessage(s) sent and 0 alert\n\n```\n\n\nFrom this message we learn that rule `TestExternalRedirect` took 47 minutes\nto complete, hence disabling this rule reduces the scan duration by about 47\nminutes.\n\n\nWe can disable individual rules with the environment variable\n`DAST_EXCLUDE_RULES`. Here is an example:\n\n\n```yaml\n\nvariables:\n  DAST_EXCLUDE_RULES=”41,42,43,10027,...,90019”\n```\n\n\n`DAST_EXCLUDE_RULES` takes a comma-separated list of rule ids. You can find\nthe id of a particular rule in the summary printed to the job log:\n\n\n```\n\nPASS: External Redirect [20019]\n\n…\n\nSUMMARY - PASS: 106 | WARN: 2\n\n```\n\n\nWe can see from the log that rule External Redirect, which we found earlier\nto take 47 minutes, has rule id 20019. To disable this rule in addition to\nthe rules from the previous example, we would need to add it to\n`DAST_EXCLUDE_RULES` like so: \n\n\n```yaml\n\nvariables:\n  DAST_EXCLUDE_RULES=”20019,41,42,43,10027,...,90019”\n```\n\n### Parallelizing DAST jobs to further reduce pipeline duration\n\n\nTo reduce the total duration of the pipeline that is running the DAST job,\nwe can split up the rules that we want to execute into multiple DAST jobs\nand run the jobs in parallel. Below is an example that demonstrates how to\nsplit up the rules.\n\n\n```yaml\n\n# Any configuration that is shared between jobs goes here\n\n.dast-conf:\n  image:\n    name: \"registry.gitlab.com/gitlab-org/security-products/dast:1.22.1\"\n  services:\n  - name: \"gitlab/gitlab-ee:nightly\"\n    alias: gitlab\n  script:\n  - /analyze -t \"http://gitlab\"\n\n# First DAST job executing rules 6 to 10\n\ndast-1/2:\n  extends:\n  - .dast-conf\n  variables:\n    DAST_EXCLUDE_RULES: \"1,2,3,4,5\"\n\n# Second DAST job executing rules 1 to 5\n\ndast-2/2:\n  extends:\n  - .dast-conf\n  variables:\n    DAST_EXCLUDE_RULES: \"5,6,7,8,9\"\n```\n\n\nFor the sake of brevity, we assume in the example above that our DAST job\nruns rules with id 1 to 10. As described in the previous section, refer to\nthe job log to find which rules were executed (we are working on printing a\ntidy [summary of executed\nrules](https://gitlab.com/gitlab-org/gitlab/-/issues/230893)). The example\ndefines two DAST jobs `dast-1/2` and `dast-2/2`. `dast-1/2` is excluding\nrules 1 to 5 and, hence, executes rules 6 to 10. Vice versa, `dast-2/2` is\nexcluding rules 6 to 10 and, hence, executes rules 1 to 5.\n\n\nFollowing the same pattern, you can split up the rules into as many jobs as\nnecessary, keeping the rules executed in a job mutually exclusive with\nrespect to all other jobs.\n\n\nNote that new releases of GitLab DAST may contain new rules, which will get\nexecuted if the rule ids are not manually added to `DAST_EXCLUDE_RULES`. In\nthe example above, we pinned the version of the DAST image to a specific\nversion using the `image` keyword. This allows us to review new releases\nmanually and adjust `DAST_EXCLUDE_RULES` as necessary before upgrading to a\nnew DAST version.\n\n\nWhen running multiple DAST jobs in parallel against the same target\napplication, make sure that the application isn’t overloaded and becomes a\nbottleneck. If you observe connection timeouts in the DAST job logs, chances\nare your target site is overloaded. To mitigate this issue, consider\nspinning up additional instances of your target application and distribute\nthe test load among the instances. GitLab CI offers, through the\n[`services`](https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service)\nkeyword, a convenient way of creating a dedicated application instance for\neach DAST job. In the example above, we start a dedicated GitLab instance\nfor each DAST job with:\n\n\n```yaml\n  services:\n  - name: \"gitlab/gitlab-ee:nightly\"\n    alias: gitlab\n```\n\n## Summary\n\n\nIn this blog post, we walked you through common challenges encountered when\ntesting complex web applications with DAST and solutions that worked well\nfor our internal projects at GitLab. \n\n\nAs we continue and broaden our use of DAST full scans within GitLab and our\nSecurity department, we’re excited to identify vulnerabilities in GitLab\nearlier in the SDLC and look forward to sharing interesting findings with\nthe community. In addition, we take our lessons learned from setting up DAST\nfull scans back to our engineering team to continue improving user\nexperience. We also plan to explore additional dynamic testing techniques\nsuch as\n[fuzzing](https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing/)\nto complement our DAST results.\n\n\nIs there a problem area that you’ve encountered or solution for fine-tuning\nDAST full scans we've missed that's worked well for you? We want to hear\nabout it and would love your feedback below in the comments.\n\n\nCover image by [Pixabay](https://www.pexels.com/@pixabay) on\n[Pexels](https://www.pexels.com/photo/blur-bowed-stringed-instrument-classic-classical-237454/)\n\n{: .note}\n","security",[21,23,24],"security research","open source",{"slug":26,"featured":6,"template":27},"how-to-configure-dast-full-scans-for-complex-web-applications","BlogPost","content:en-us:blog:how-to-configure-dast-full-scans-for-complex-web-applications.yml","yaml","How To Configure Dast Full Scans For Complex Web Applications","content","en-us/blog/how-to-configure-dast-full-scans-for-complex-web-applications.yml","en-us/blog/how-to-configure-dast-full-scans-for-complex-web-applications","yml",{"_path":36,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"data":38,"_id":460,"_type":29,"title":461,"_source":31,"_file":462,"_stem":463,"_extension":34},"/shared/en-us/main-navigation","en-us",{"logo":39,"freeTrial":44,"sales":49,"login":54,"items":59,"search":391,"minimal":422,"duo":441,"pricingDeployment":450},{"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,104,202,207,312,372],{"text":61,"config":62,"cards":64,"footer":87},"Platform",{"dataNavLevelOne":63},"platform",[65,71,79],{"title":61,"description":66,"link":67},"The most comprehensive AI-powered DevSecOps Platform",{"text":68,"config":69},"Explore our Platform",{"href":70,"dataGaName":63,"dataGaLocation":43},"/platform/",{"title":72,"description":73,"link":74},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":75,"config":76},"Meet GitLab Duo",{"href":77,"dataGaName":78,"dataGaLocation":43},"/gitlab-duo/","gitlab duo ai",{"title":80,"description":81,"link":82},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":83,"config":84},"Learn more",{"href":85,"dataGaName":86,"dataGaLocation":43},"/why-gitlab/","why gitlab",{"title":88,"items":89},"Get started with",[90,95,100],{"text":91,"config":92},"Platform Engineering",{"href":93,"dataGaName":94,"dataGaLocation":43},"/solutions/platform-engineering/","platform engineering",{"text":96,"config":97},"Developer Experience",{"href":98,"dataGaName":99,"dataGaLocation":43},"/developer-experience/","Developer experience",{"text":101,"config":102},"MLOps",{"href":103,"dataGaName":101,"dataGaLocation":43},"/topics/devops/the-role-of-ai-in-devops/",{"text":105,"left":106,"config":107,"link":109,"lists":113,"footer":184},"Product",true,{"dataNavLevelOne":108},"solutions",{"text":110,"config":111},"View all Solutions",{"href":112,"dataGaName":108,"dataGaLocation":43},"/solutions/",[114,139,163],{"title":115,"description":116,"link":117,"items":122},"Automation","CI/CD and automation to accelerate deployment",{"config":118},{"icon":119,"href":120,"dataGaName":121,"dataGaLocation":43},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[123,127,131,135],{"text":124,"config":125},"CI/CD",{"href":126,"dataGaLocation":43,"dataGaName":124},"/solutions/continuous-integration/",{"text":128,"config":129},"AI-Assisted Development",{"href":77,"dataGaLocation":43,"dataGaName":130},"AI assisted development",{"text":132,"config":133},"Source Code Management",{"href":134,"dataGaLocation":43,"dataGaName":132},"/solutions/source-code-management/",{"text":136,"config":137},"Automated Software Delivery",{"href":120,"dataGaLocation":43,"dataGaName":138},"Automated software delivery",{"title":140,"description":141,"link":142,"items":147},"Security","Deliver code faster without compromising security",{"config":143},{"href":144,"dataGaName":145,"dataGaLocation":43,"icon":146},"/solutions/security-compliance/","security and compliance","ShieldCheckLight",[148,153,158],{"text":149,"config":150},"Application Security Testing",{"href":151,"dataGaName":152,"dataGaLocation":43},"/solutions/application-security-testing/","Application security testing",{"text":154,"config":155},"Software Supply Chain Security",{"href":156,"dataGaLocation":43,"dataGaName":157},"/solutions/supply-chain/","Software supply chain security",{"text":159,"config":160},"Software Compliance",{"href":161,"dataGaName":162,"dataGaLocation":43},"/solutions/software-compliance/","software compliance",{"title":164,"link":165,"items":170},"Measurement",{"config":166},{"icon":167,"href":168,"dataGaName":169,"dataGaLocation":43},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[171,175,179],{"text":172,"config":173},"Visibility & Measurement",{"href":168,"dataGaLocation":43,"dataGaName":174},"Visibility and Measurement",{"text":176,"config":177},"Value Stream Management",{"href":178,"dataGaLocation":43,"dataGaName":176},"/solutions/value-stream-management/",{"text":180,"config":181},"Analytics & Insights",{"href":182,"dataGaLocation":43,"dataGaName":183},"/solutions/analytics-and-insights/","Analytics and insights",{"title":185,"items":186},"GitLab for",[187,192,197],{"text":188,"config":189},"Enterprise",{"href":190,"dataGaLocation":43,"dataGaName":191},"/enterprise/","enterprise",{"text":193,"config":194},"Small Business",{"href":195,"dataGaLocation":43,"dataGaName":196},"/small-business/","small business",{"text":198,"config":199},"Public Sector",{"href":200,"dataGaLocation":43,"dataGaName":201},"/solutions/public-sector/","public sector",{"text":203,"config":204},"Pricing",{"href":205,"dataGaName":206,"dataGaLocation":43,"dataNavLevelOne":206},"/pricing/","pricing",{"text":208,"config":209,"link":211,"lists":215,"feature":299},"Resources",{"dataNavLevelOne":210},"resources",{"text":212,"config":213},"View all resources",{"href":214,"dataGaName":210,"dataGaLocation":43},"/resources/",[216,249,271],{"title":217,"items":218},"Getting started",[219,224,229,234,239,244],{"text":220,"config":221},"Install",{"href":222,"dataGaName":223,"dataGaLocation":43},"/install/","install",{"text":225,"config":226},"Quick start guides",{"href":227,"dataGaName":228,"dataGaLocation":43},"/get-started/","quick setup checklists",{"text":230,"config":231},"Learn",{"href":232,"dataGaLocation":43,"dataGaName":233},"https://university.gitlab.com/","learn",{"text":235,"config":236},"Product documentation",{"href":237,"dataGaName":238,"dataGaLocation":43},"https://docs.gitlab.com/","product documentation",{"text":240,"config":241},"Best practice videos",{"href":242,"dataGaName":243,"dataGaLocation":43},"/getting-started-videos/","best practice videos",{"text":245,"config":246},"Integrations",{"href":247,"dataGaName":248,"dataGaLocation":43},"/integrations/","integrations",{"title":250,"items":251},"Discover",[252,257,261,266],{"text":253,"config":254},"Customer success stories",{"href":255,"dataGaName":256,"dataGaLocation":43},"/customers/","customer success stories",{"text":258,"config":259},"Blog",{"href":260,"dataGaName":5,"dataGaLocation":43},"/blog/",{"text":262,"config":263},"Remote",{"href":264,"dataGaName":265,"dataGaLocation":43},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":267,"config":268},"TeamOps",{"href":269,"dataGaName":270,"dataGaLocation":43},"/teamops/","teamops",{"title":272,"items":273},"Connect",[274,279,284,289,294],{"text":275,"config":276},"GitLab Services",{"href":277,"dataGaName":278,"dataGaLocation":43},"/services/","services",{"text":280,"config":281},"Community",{"href":282,"dataGaName":283,"dataGaLocation":43},"/community/","community",{"text":285,"config":286},"Forum",{"href":287,"dataGaName":288,"dataGaLocation":43},"https://forum.gitlab.com/","forum",{"text":290,"config":291},"Events",{"href":292,"dataGaName":293,"dataGaLocation":43},"/events/","events",{"text":295,"config":296},"Partners",{"href":297,"dataGaName":298,"dataGaLocation":43},"/partners/","partners",{"backgroundColor":300,"textColor":301,"text":302,"image":303,"link":307},"#2f2a6b","#fff","Insights for the future of software development",{"altText":304,"config":305},"the source promo card",{"src":306},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":308,"config":309},"Read the latest",{"href":310,"dataGaName":311,"dataGaLocation":43},"/the-source/","the source",{"text":313,"config":314,"lists":316},"Company",{"dataNavLevelOne":315},"company",[317],{"items":318},[319,324,330,332,337,342,347,352,357,362,367],{"text":320,"config":321},"About",{"href":322,"dataGaName":323,"dataGaLocation":43},"/company/","about",{"text":325,"config":326,"footerGa":329},"Jobs",{"href":327,"dataGaName":328,"dataGaLocation":43},"/jobs/","jobs",{"dataGaName":328},{"text":290,"config":331},{"href":292,"dataGaName":293,"dataGaLocation":43},{"text":333,"config":334},"Leadership",{"href":335,"dataGaName":336,"dataGaLocation":43},"/company/team/e-group/","leadership",{"text":338,"config":339},"Team",{"href":340,"dataGaName":341,"dataGaLocation":43},"/company/team/","team",{"text":343,"config":344},"Handbook",{"href":345,"dataGaName":346,"dataGaLocation":43},"https://handbook.gitlab.com/","handbook",{"text":348,"config":349},"Investor relations",{"href":350,"dataGaName":351,"dataGaLocation":43},"https://ir.gitlab.com/","investor relations",{"text":353,"config":354},"Trust Center",{"href":355,"dataGaName":356,"dataGaLocation":43},"/security/","trust center",{"text":358,"config":359},"AI Transparency Center",{"href":360,"dataGaName":361,"dataGaLocation":43},"/ai-transparency-center/","ai transparency center",{"text":363,"config":364},"Newsletter",{"href":365,"dataGaName":366,"dataGaLocation":43},"/company/contact/","newsletter",{"text":368,"config":369},"Press",{"href":370,"dataGaName":371,"dataGaLocation":43},"/press/","press",{"text":373,"config":374,"lists":375},"Contact us",{"dataNavLevelOne":315},[376],{"items":377},[378,381,386],{"text":50,"config":379},{"href":52,"dataGaName":380,"dataGaLocation":43},"talk to sales",{"text":382,"config":383},"Get help",{"href":384,"dataGaName":385,"dataGaLocation":43},"/support/","get help",{"text":387,"config":388},"Customer portal",{"href":389,"dataGaName":390,"dataGaLocation":43},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":392,"login":393,"suggestions":400},"Close",{"text":394,"link":395},"To search repositories and projects, login to",{"text":396,"config":397},"gitlab.com",{"href":57,"dataGaName":398,"dataGaLocation":399},"search login","search",{"text":401,"default":402},"Suggestions",[403,405,409,411,415,419],{"text":72,"config":404},{"href":77,"dataGaName":72,"dataGaLocation":399},{"text":406,"config":407},"Code Suggestions (AI)",{"href":408,"dataGaName":406,"dataGaLocation":399},"/solutions/code-suggestions/",{"text":124,"config":410},{"href":126,"dataGaName":124,"dataGaLocation":399},{"text":412,"config":413},"GitLab on AWS",{"href":414,"dataGaName":412,"dataGaLocation":399},"/partners/technology-partners/aws/",{"text":416,"config":417},"GitLab on Google Cloud",{"href":418,"dataGaName":416,"dataGaLocation":399},"/partners/technology-partners/google-cloud-platform/",{"text":420,"config":421},"Why GitLab?",{"href":85,"dataGaName":420,"dataGaLocation":399},{"freeTrial":423,"mobileIcon":428,"desktopIcon":433,"secondaryButton":436},{"text":424,"config":425},"Start free trial",{"href":426,"dataGaName":48,"dataGaLocation":427},"https://gitlab.com/-/trials/new/","nav",{"altText":429,"config":430},"Gitlab Icon",{"src":431,"dataGaName":432,"dataGaLocation":427},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":429,"config":434},{"src":435,"dataGaName":432,"dataGaLocation":427},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":437,"config":438},"Get Started",{"href":439,"dataGaName":440,"dataGaLocation":427},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":442,"mobileIcon":446,"desktopIcon":448},{"text":443,"config":444},"Learn more about GitLab Duo",{"href":77,"dataGaName":445,"dataGaLocation":427},"gitlab duo",{"altText":429,"config":447},{"src":431,"dataGaName":432,"dataGaLocation":427},{"altText":429,"config":449},{"src":435,"dataGaName":432,"dataGaLocation":427},{"freeTrial":451,"mobileIcon":456,"desktopIcon":458},{"text":452,"config":453},"Back to pricing",{"href":205,"dataGaName":454,"dataGaLocation":427,"icon":455},"back to pricing","GoBack",{"altText":429,"config":457},{"src":431,"dataGaName":432,"dataGaLocation":427},{"altText":429,"config":459},{"src":435,"dataGaName":432,"dataGaLocation":427},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":465,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"title":466,"button":467,"image":472,"config":476,"_id":478,"_type":29,"_source":31,"_file":479,"_stem":480,"_extension":34},"/shared/en-us/banner","is now in public beta!",{"text":468,"config":469},"Try the Beta",{"href":470,"dataGaName":471,"dataGaLocation":43},"/gitlab-duo/agent-platform/","duo banner",{"altText":473,"config":474},"GitLab Duo Agent Platform",{"src":475},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":477},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":482,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"data":483,"_id":687,"_type":29,"title":688,"_source":31,"_file":689,"_stem":690,"_extension":34},"/shared/en-us/main-footer",{"text":484,"source":485,"edit":491,"contribute":496,"config":501,"items":506,"minimal":679},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":486,"config":487},"View page source",{"href":488,"dataGaName":489,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":492,"config":493},"Edit this page",{"href":494,"dataGaName":495,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":497,"config":498},"Please contribute",{"href":499,"dataGaName":500,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":502,"facebook":503,"youtube":504,"linkedin":505},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[507,530,586,615,649],{"title":61,"links":508,"subMenu":513},[509],{"text":510,"config":511},"DevSecOps platform",{"href":70,"dataGaName":512,"dataGaLocation":490},"devsecops platform",[514],{"title":203,"links":515},[516,520,525],{"text":517,"config":518},"View plans",{"href":205,"dataGaName":519,"dataGaLocation":490},"view plans",{"text":521,"config":522},"Why Premium?",{"href":523,"dataGaName":524,"dataGaLocation":490},"/pricing/premium/","why premium",{"text":526,"config":527},"Why Ultimate?",{"href":528,"dataGaName":529,"dataGaLocation":490},"/pricing/ultimate/","why ultimate",{"title":531,"links":532},"Solutions",[533,538,540,542,547,552,556,559,563,568,570,573,576,581],{"text":534,"config":535},"Digital transformation",{"href":536,"dataGaName":537,"dataGaLocation":490},"/topics/digital-transformation/","digital transformation",{"text":149,"config":539},{"href":151,"dataGaName":149,"dataGaLocation":490},{"text":138,"config":541},{"href":120,"dataGaName":121,"dataGaLocation":490},{"text":543,"config":544},"Agile development",{"href":545,"dataGaName":546,"dataGaLocation":490},"/solutions/agile-delivery/","agile delivery",{"text":548,"config":549},"Cloud transformation",{"href":550,"dataGaName":551,"dataGaLocation":490},"/topics/cloud-native/","cloud transformation",{"text":553,"config":554},"SCM",{"href":134,"dataGaName":555,"dataGaLocation":490},"source code management",{"text":124,"config":557},{"href":126,"dataGaName":558,"dataGaLocation":490},"continuous integration & delivery",{"text":560,"config":561},"Value stream management",{"href":178,"dataGaName":562,"dataGaLocation":490},"value stream management",{"text":564,"config":565},"GitOps",{"href":566,"dataGaName":567,"dataGaLocation":490},"/solutions/gitops/","gitops",{"text":188,"config":569},{"href":190,"dataGaName":191,"dataGaLocation":490},{"text":571,"config":572},"Small business",{"href":195,"dataGaName":196,"dataGaLocation":490},{"text":574,"config":575},"Public sector",{"href":200,"dataGaName":201,"dataGaLocation":490},{"text":577,"config":578},"Education",{"href":579,"dataGaName":580,"dataGaLocation":490},"/solutions/education/","education",{"text":582,"config":583},"Financial services",{"href":584,"dataGaName":585,"dataGaLocation":490},"/solutions/finance/","financial services",{"title":208,"links":587},[588,590,592,594,597,599,601,603,605,607,609,611,613],{"text":220,"config":589},{"href":222,"dataGaName":223,"dataGaLocation":490},{"text":225,"config":591},{"href":227,"dataGaName":228,"dataGaLocation":490},{"text":230,"config":593},{"href":232,"dataGaName":233,"dataGaLocation":490},{"text":235,"config":595},{"href":237,"dataGaName":596,"dataGaLocation":490},"docs",{"text":258,"config":598},{"href":260,"dataGaName":5,"dataGaLocation":490},{"text":253,"config":600},{"href":255,"dataGaName":256,"dataGaLocation":490},{"text":262,"config":602},{"href":264,"dataGaName":265,"dataGaLocation":490},{"text":275,"config":604},{"href":277,"dataGaName":278,"dataGaLocation":490},{"text":267,"config":606},{"href":269,"dataGaName":270,"dataGaLocation":490},{"text":280,"config":608},{"href":282,"dataGaName":283,"dataGaLocation":490},{"text":285,"config":610},{"href":287,"dataGaName":288,"dataGaLocation":490},{"text":290,"config":612},{"href":292,"dataGaName":293,"dataGaLocation":490},{"text":295,"config":614},{"href":297,"dataGaName":298,"dataGaLocation":490},{"title":313,"links":616},[617,619,621,623,625,627,629,633,638,640,642,644],{"text":320,"config":618},{"href":322,"dataGaName":315,"dataGaLocation":490},{"text":325,"config":620},{"href":327,"dataGaName":328,"dataGaLocation":490},{"text":333,"config":622},{"href":335,"dataGaName":336,"dataGaLocation":490},{"text":338,"config":624},{"href":340,"dataGaName":341,"dataGaLocation":490},{"text":343,"config":626},{"href":345,"dataGaName":346,"dataGaLocation":490},{"text":348,"config":628},{"href":350,"dataGaName":351,"dataGaLocation":490},{"text":630,"config":631},"Sustainability",{"href":632,"dataGaName":630,"dataGaLocation":490},"/sustainability/",{"text":634,"config":635},"Diversity, inclusion and belonging (DIB)",{"href":636,"dataGaName":637,"dataGaLocation":490},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":353,"config":639},{"href":355,"dataGaName":356,"dataGaLocation":490},{"text":363,"config":641},{"href":365,"dataGaName":366,"dataGaLocation":490},{"text":368,"config":643},{"href":370,"dataGaName":371,"dataGaLocation":490},{"text":645,"config":646},"Modern Slavery Transparency Statement",{"href":647,"dataGaName":648,"dataGaLocation":490},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":650,"links":651},"Contact Us",[652,655,657,659,664,669,674],{"text":653,"config":654},"Contact an expert",{"href":52,"dataGaName":53,"dataGaLocation":490},{"text":382,"config":656},{"href":384,"dataGaName":385,"dataGaLocation":490},{"text":387,"config":658},{"href":389,"dataGaName":390,"dataGaLocation":490},{"text":660,"config":661},"Status",{"href":662,"dataGaName":663,"dataGaLocation":490},"https://status.gitlab.com/","status",{"text":665,"config":666},"Terms of use",{"href":667,"dataGaName":668,"dataGaLocation":490},"/terms/","terms of use",{"text":670,"config":671},"Privacy statement",{"href":672,"dataGaName":673,"dataGaLocation":490},"/privacy/","privacy statement",{"text":675,"config":676},"Cookie preferences",{"dataGaName":677,"dataGaLocation":490,"id":678,"isOneTrustButton":106},"cookie preferences","ot-sdk-btn",{"items":680},[681,683,685],{"text":665,"config":682},{"href":667,"dataGaName":668,"dataGaLocation":490},{"text":670,"config":684},{"href":672,"dataGaName":673,"dataGaLocation":490},{"text":675,"config":686},{"dataGaName":677,"dataGaLocation":490,"id":678,"isOneTrustButton":106},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[692],{"_path":693,"_dir":694,"_draft":6,"_partial":6,"_locale":7,"content":695,"config":699,"_id":701,"_type":29,"title":18,"_source":31,"_file":702,"_stem":703,"_extension":34},"/en-us/blog/authors/dennis-appelt","authors",{"name":18,"config":696},{"headshot":697,"ctfId":698},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749672032/Blog/Author%20Headshots/dappelt-headshot.jpg","dappelt",{"template":700},"BlogAuthor","content:en-us:blog:authors:dennis-appelt.yml","en-us/blog/authors/dennis-appelt.yml","en-us/blog/authors/dennis-appelt",{"_path":705,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"header":706,"eyebrow":707,"blurb":708,"button":709,"secondaryButton":713,"_id":715,"_type":29,"title":716,"_source":31,"_file":717,"_stem":718,"_extension":34},"/shared/en-us/next-steps","Start shipping better software faster","50%+ of the Fortune 100 trust GitLab","See what your team can do with the intelligent\n\n\nDevSecOps platform.\n",{"text":45,"config":710},{"href":711,"dataGaName":48,"dataGaLocation":712},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":50,"config":714},{"href":52,"dataGaName":53,"dataGaLocation":712},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1758326230779]