[{"data":1,"prerenderedAt":718},["ShallowReactive",2],{"/en-us/blog/american-fuzzy-lop-on-gitlab/":3,"navigation-en-us":35,"banner-en-us":464,"footer-en-us":481,"Luka Trbojevic":691,"next-steps-en-us":703},{"_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/american-fuzzy-lop-on-gitlab","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"GitLab automates instrumented fuzzing via American Fuzzy Lop","An example of how to automate instrumented fuzzing with American Fuzzy Lop using pipelines.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680723/Blog/Hero%20Images/aerial-shot-birds-eye-view.jpg","https://about.gitlab.com/blog/american-fuzzy-lop-on-gitlab","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"American Fuzzy Lop on GitLab: Automating instrumented fuzzing using pipelines\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Luka Trbojevic\"}],\n        \"datePublished\": \"2019-08-14\",\n      }",{"title":17,"description":10,"authors":18,"heroImage":11,"date":20,"body":21,"category":22,"tags":23},"American Fuzzy Lop on GitLab: Automating instrumented fuzzing using pipelines",[19],"Luka Trbojevic","2019-08-14","This year at [BSides Kansas City](https://2019.bsideskc.org/), many of my\nconversations were about fuzzing and integrating security into the [DevOps\nprocess](/topics/devops/). Fuzzing has been around for a very long time.\nBack in 2006, I wrote my first (very simple) fuzzer to mutate .zip files and\npass them to anti-virus programs; even at that time, the case for fuzzing\nhad been made many years prior. Today, [American Fuzzy Lop\n(AFL)](http://lcamtuf.coredump.cx/afl/), written by Michal Zalewski, stands\nas one of the best fuzzers available, and is one of my favorite tools.\n\n\nAnecdotally, I've been seeing good arguments made for the adoption of\nfuzzing as part of the software security lifecycle more frequently than ever\nbefore. At BSides Kansas City, I listened to an interesting conversation at\nthe speakers' dinner where the case was made that fuzzing is reduced to a\nniche, nice-to-have, wishlist item incorporated into workflows by exploit\ndevelopers and only the largest of enterprises. I largely agree, but I like\nto think of why that's the case.\n\n\nMy general sense is that instrumented fuzzing, as a function of the software\nlifecycle, is still fraught with too much friction for widespread adoption.\nFor something to take hold at scale, be useful to a large number of people,\nand have its benefits passed down to consumers, it needs to be quick and\nsimple. Right now, fuzzing as something an **organization** does as part of\nits standard practice is not quick or simple. So, even if you have someone\nwell-versed in fuzzing and exploit development, chances are fuzzing won’t\nsurvive as an organizational function.\n\n\nIn the hope that we can move the conversation forward, I wanted to give back\nsomething actionable – yet simple – to help folks incorporate fuzzing into\ntheir workflows. I’ve always found practical, hands-on examples to be the\nmost helpful, so I put together a baseline sample showing how fuzzing with\nAFL can be automated as part of a pipeline.\n\n\nTwo important notes:\n\n\n* This blog isn’t an introduction to instrumented fuzzing and assumes you\nhave a good understanding of it already, including what a test harness is\nand how to write one.\n\n* [Fuzzing as a feature of GitLab is in the\nworks](https://gitlab.com/gitlab-org/gitlab-ee/issues/10852), but it's not\nhere just yet. Also, the [first\niteration](https://gitlab.com/gitlab-org/gitlab-ee/issues/8453) doesn't seem\nto include instrumented fuzzing.\n\n\nYou can find all code, including the Dockerfile, and detailed\nsetup/modification instructions in the [AFL-GitLab\nrepository](https://gitlab.com/ltrbojevic/afl-gitlab). **Please familiarize\nyourself with the background in the repository first!**\n\n\n## Docker image setup\n\n\nI prefer to work with Docker images, so I’ve used the [Docker\nexecutor](https://docs.gitlab.com/runner/executors/docker.html). AFL, your\ncode, the test harness (if applicable), and the controlling Python script\n(more on that below) are in your Docker image.\n\n\nFor this example, we’re using Ubuntu 16.04. You can use any operating system\nyou prefer. I run Ubuntu 16.04 for my fuzzing jobs, which is why I’ve used\nit here:\n\n\n`FROM ubuntu:16.04`\n\n\nI copy a local `fuzzing/` folder with all of my files to `/usr/src/` in the\nDocker image. This can be changed to whatever works for you:\n\n\n`COPY fuzzing/ /usr/src/`\n\n\nI set the user as `root` because I just want it to work. Customize this per\nyour operating system, threat model, and risk tolerance:\n\n\n`USER root`\n\n\nThen just install whatever packages you need:\n\n\n```\n\nRUN apt-get update && apt-get install -y \\\n  sudo \\\n  software-properties-common \\\n  build-essential\n```\n\n\nNote that this image is optimized for compatibility and efficiency only.\n\n\n## Our sample target program\n\n\nFor this example, we’re going to be fuzzing\n[vulnerable.c](https://gitlab.com/ltrbojevic/afl-gitlab/blob/master/fuzzing/afl-gitlab/vulnerable.c).\nIt features a total absence of security and C best practice and is designed\nto intentionally generate at least one unique crash within the first few\nseconds of fuzzing. It’s a quick and simple way to verify everything else is\nworking.\n\n\n## Setting up AFL\n\n\nInstrumenting your program is done within the `.gitlab-ci.yml` file as part\nof the `before_script` parameter:\n\n\n```\n\nrun-afl:\n\nstage: run-afl\n\nbefore_script:\n\n- cd /usr/src/afl-2.52b\n\n- make\n\n- make install\n\n- cd /usr/src/afl-gitlab\n\n- CC=/usr/src/afl-2.52b/afl-gcc AFL_HARDEN=1 make\n\n- echo core >/proc/sys/kernel/core_pattern\n\n- echo $CI_PROJECT_DIR\n\n```\n\n\nI include `echo $CI_PROJECT_DIR` as a troubleshooting measure (more below).\n\n\n### A note on performance\n\n\nThis specific example uses GitLab.com [Shared\nRunners](https://docs.gitlab.com/ee/ci/runners/#shared-runners) for\ndemonstration’s sake. The performance limitations of Shared Runners in the\ncontext of fuzzing make it infeasible to run instrumented fuzzing jobs in a\nperformant way. Instead, you could consider using a self-hosted runner.\n\n\n## Initializing AFL\n\n\nThe problem with initiating AFL in `.gitlab-ci.yml` is AFL will continue to\nrun until interrupted, so it must be stopped programmatically and that stop\nmust be configurable to only run after a defined amount of time.\n\n\nTo solve this problem, we can have the pipeline run a script to manage the\nexecution and handling of AFL. I prefer to use Python, but you can use any\nlanguage you like. In Python, we can use the `time.sleep()` function. The\nPython script will initiate AFL and `sleep()` will be used to run AFL for\nwhatever length of time you set. Afterwards, AFL will be stopped.\n\n\nIn `.gitlab.ci-yml`, we run this script **after** AFL is installed and our\nprogram is instrumented. We do this by doing the instrumentation using the\n`before_script` parameter and running the Python script using the `script`\nparameter:\n\n\n```\n\nscript:\n\n- python3 /usr/src/fuzzing/afl-gitlab/afl-gitlab.py\n\n```\n\n\n`afl-gitlab.py` is where the magic happens and it serves as the control\ncenter where the handling and synchronization of the different events that\nneed to happen are managed and customized.\n\n\nTo start AFL, we use `subprocess.Popen()` to run the command:\n\n\n```subprocess.Popen([\"afl-fuzz\", \"-i\", \"inputs\", \"-o\", \"outputs\",\n\"./vulnerable\"])```\n\n\nTo control exactly how long AFL will run, we use `time.sleep()` -- in this\nexample, it’s 30 seconds:\n\n\n```\n\ntime.sleep(30)\n\n```\n\n\nAfter that, we need to stop AFL in a way that doesn’t cause the pipeline to\nfail. If you exit `afl-python.py` itself like you might do locally, the job\nwill fail. To get around this, we use `subprocess.Popen()` to stop AFL:\n\n\n```\n\nsubprocess.Popen([\"pkill\", \"-f\", \"afl\"])\n\n```\n\n\nLastly, we exit the `afl-python.py` in a way that doesn’t cause the job to\nfail:\n\n\n```\n\nos._exit(0)\n\n```\n\n\nIt’s important your script doesn’t cause the job to fail because everything\nelse that needs to happen, won’t:\n\n\n![job fail\nmessage](https://about.gitlab.com/images/blogimages/jobfail.png){:\n.shadow.medium.center}\n\n\nJust in case the job fails and you don’t want your entire pipeline to fail,\nI set `allow_failure: true` in the `.gitlab-ci.yml` file.\n\n\n## Collecting AFL output as a pipeline artifact\n\n\nRunning AFL has no value if the output can’t be collected in a\nworkflow-friendly way, so we’ll use [pipeline\nartifacts](https://docs.gitlab.com/ee/ci/pipelines/job_artifacts.html). The\nentire artifact collection process can be defined in the `.gitlab-ci-yml`\nfile.\n\n\nFirst, using the `after_scripts` parameter, which will run after\n`afl-gitlab.py` exits, we copy the `outputs` folder to a location in\n`$CI_PROJECT_DIR` (thus the `echo $CI_PROJECT_DIR done earlier`). This is\nimportant because you may run into [artifact not found\nissues](https://stackoverflow.com/questions/47490688/gitlab-ci-artifacts-not-found):\n\n\n```\n\nafter_script:\n  - cp -a /usr/src/afl-gitlab/outputs $CI_PROJECT_DIR\n```\n\nThen we simply collect the `outputs` folder as an artifact:\n\n\n```\n\nartifacts:\n\npaths:\n\n- $CI_PROJECT_DIR/outputs\n\n```\n\n\nYour output will then be viewable like any other pipeline artifact:\n\n\n![output\nartifact](https://about.gitlab.com/images/blogimages/output-artifact.png){:\n.shadow.medium.center}\n\n\n## Creating issues for every unique crash\n\n\nTo make this a truly automated workflow, you could use the [GitLab\nAPI](https://docs.gitlab.com/ee/api/) to create an issue for every unique\ncrash. At this time, I haven’t had the time to invest heavily in this, but\nI’ll have to circle back when I do.\n\n\nHaving played with the artifacts API for only a few brief moments, the path\nof least resistance seems to be adding the logic to `afl-gitlab.py`\n**prior** to the artifact collection.\n\n\nFor a specific example on how to use `python-gitlab` to create issues, check\nout [an issue generator script I wrote for the HIPAA Audit\nProtocol](https://gitlab.com/ltrbojevic/hipaa-audit-protocol-issue-generator).\n\n\n## Distributed fuzzing and multi-system parallelization\n\n\nThe basic principles of multi-system parallelization apply whether you're\nrunning distributed fuzzing jobs manually or automating them on GitLab.\nWhile I haven't had a chance to port my personal workflows to GitLab yet, a\nquick glance tells me it’s likely possible.\n\n\nUsing `afl-gitlab.py`, you could run a separate script to handle the\ndeployment, configuration, and de-provisioning of -S mode instances. My\ninitial preference would be to run a second Python script – let's call it\n`afl-gitlab-s.py`  that would use `python-terraform` to provision and\ndeprovision the infrastructure. Fabric can be used to configure the\ninstances, start AFL, and so on.\n\n\nThere would have to be some thought put into the timing and orchestration\nbetween the two scripts. It's also important to note: your synchronization\nscripts have to be timed so as not to de-provision -S mode instances before\na synchronization event occurs; especially if you opt for staged\nsynchronization.\n\n\nLists make the most sense to me, so in other words:\n\n1. A Runner job runs `afl-gitlab.py`\n\n2. `afl-gitlab.py` starts a second script, `afl-gitlab-s.py`\n\n3. `afl-gitlab-s.py` does a short sleep to allow `afl-gitlab.py` to run the\n-M mode instance\n\n3. `afl-gitlab-s.py` uses `python-terraform` to provision -S mode instances\n\n4. `afl-gitlab-s.py` then uses Fabric to configure the -S mode instances\n(e.g., set up synchronization scripts) and start AFL\n\n5. `afl-gitlab-s.py` sleeps for 1:55 hrs\n\n6. `afl-gitlab-s.py` de-provisions the -S mode instances\n\n7. `afl-gitlab.py` ends the -M mode instance fuzzing\n\n\nNote that I'm assuming you've modified your synchronization scripts to\ntransfer `crashes` and `hangs` to the -M mode instance. Please remember that\nthe out-of-the-box synchronization scripts transfer `queue`, so unless\nyou've modified your script to transfer other folder contents as well, you\nmay lose findings when the -S mode instances are de-provisioned.\n\n\n## Automating advanced output triage and analysis\n\n\nMany triage and initial analysis workflows can be, and are, automated. My\npersonal workflow includes a combination AFL's crash explorer, pwndbg, and\nradare2. I’ve condensed most of my initial triage to a single Python tool.\nThe tool could be run as a Runner job, either on the Runner instance itself\nor, as above with the -S mode instances, offloaded to another box with the\nresults returned to the Runner instance. Given that, and regardless of the\nlanguage of your toolset, automating output triage and initial analysis\nseems to be doable with some tinkering.\n\n\nMuch like automatically creating an issue for every unique crash found, I’ve\nnot yet had the time to focus on this and give it a go, but I’ll circle back\nand add it when I can.\n\n\n## Some final thoughts\n\n\nThere's a whole bunch we could automate and make more accessible in the\nfuzzing space. In the interest of reaching and benefiting the largest number\nof people, I’d love to see GitLab have mature fuzzing features that are\nhelpful to developers and security folk alike. To help move that forward, I\nthink community involvement in key. If you have the inclination please\ncontribute to our\n[direction](https://gitlab.com/gitlab-org/gitlab-ee/issues/10852). And if,\ninstead, you want to take this example and expand it outside of the GitLab\necosystem, please do and tell us how it went!\n\n\nPhoto by [Tom\nFisk](https://www.pexels.com/@tomfisk?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels)\non [Pexels](https://www.pexels.com)\n\n{: .note}\n","security",[24,22],"inside GitLab",{"slug":26,"featured":6,"template":27},"american-fuzzy-lop-on-gitlab","BlogPost","content:en-us:blog:american-fuzzy-lop-on-gitlab.yml","yaml","American Fuzzy Lop On Gitlab","content","en-us/blog/american-fuzzy-lop-on-gitlab.yml","en-us/blog/american-fuzzy-lop-on-gitlab","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":698,"_id":700,"_type":29,"title":19,"_source":31,"_file":701,"_stem":702,"_extension":34},"/en-us/blog/authors/luka-trbojevic","authors",{"name":19,"config":696},{"headshot":7,"ctfId":697},"ltrbojevic",{"template":699},"BlogAuthor","content:en-us:blog:authors:luka-trbojevic.yml","en-us/blog/authors/luka-trbojevic.yml","en-us/blog/authors/luka-trbojevic",{"_path":704,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"header":705,"eyebrow":706,"blurb":707,"button":708,"secondaryButton":712,"_id":714,"_type":29,"title":715,"_source":31,"_file":716,"_stem":717,"_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":709},{"href":710,"dataGaName":48,"dataGaLocation":711},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":50,"config":713},{"href":52,"dataGaName":53,"dataGaLocation":711},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1758653926735]