{"id":26958568,"url":"https://github.com/chainguard-dev/ghscan","last_synced_at":"2025-04-03T04:20:02.020Z","repository":{"id":283180965,"uuid":"950600200","full_name":"chainguard-dev/ghscan","owner":"chainguard-dev","description":"Scan GitHub Actions Workflow logs for IOCs","archived":false,"fork":false,"pushed_at":"2025-04-02T12:50:26.000Z","size":56,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-02T13:43:34.059Z","etag":null,"topics":["actions","changed-files","detection","github-actions","ioc","logs","scanner","secrets","supply-chain","supply-chain-attacks","supply-chain-security","workflow"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chainguard-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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}},"created_at":"2025-03-18T12:10:55.000Z","updated_at":"2025-04-02T12:50:28.000Z","dependencies_parsed_at":"2025-04-02T13:43:36.392Z","dependency_job_id":"d37566c0-506f-44f7-b7c8-8f0753635a29","html_url":"https://github.com/chainguard-dev/ghscan","commit_stats":null,"previous_names":["chainguard-dev/tj-scan","chainguard-dev/ghscan"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainguard-dev%2Fghscan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainguard-dev%2Fghscan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainguard-dev%2Fghscan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainguard-dev%2Fghscan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chainguard-dev","download_url":"https://codeload.github.com/chainguard-dev/ghscan/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246933870,"owners_count":20857143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["actions","changed-files","detection","github-actions","ioc","logs","scanner","secrets","supply-chain","supply-chain-attacks","supply-chain-security","workflow"],"created_at":"2025-04-03T04:20:01.257Z","updated_at":"2025-04-03T04:20:02.001Z","avatar_url":"https://github.com/chainguard-dev.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ghscan\nScan GitHub Workflow logs for IOCs via strings or regex.\n\nNotes:\n- This script should not be seen as a universal detector of compromise; rather, a single result likely indicates that other Workflow runs in the search window were also compromised\n  - If the script detects base64 content in a Workflow's run logs as well as consecutive empty lines (no secrets leaked from the compromised action), then only the base64 data will be returned\n- This script will scan either an organization's or a repository's Workflow run logs for IOCs (double base64-encoded strings) and will attempt to decode them\n- This script was adapated from a mess of Python code that was built to scan the entirety of GitHub so there may be quirks or bugs\n- Since Workflows may no longer use the Action, this script just lists all Workflows and searches the logs during the period of time when the Action was compromised\n- This script is intended to be run using a short-lived GitHub Token from `octo-sts`\n\n## Requirements\n\n- [chainctl](https://edu.chainguard.dev/chainguard/administration/how-to-install-chainctl) installed to handle ephemeral authentication\n\n## Example `octo-sts` trust policy\n\nThe ID required for the trust policy can be retrieved with:\n```sh\n$ chainctl auth status -o json | jq .identity | tr -d '\"'\n```\n\nThe policy file will look something like this:\n```yaml\nissuer: https://issuer.enforce.dev\n# Use ONE of subject or subject_pattern\nsubject: \u003cID from above\u003e\nsubject_pattern: (\u003cID from above\u003e)\nclaim_pattern:\n  email: \".*@domain.com\"\n\npermissions:\n  actions: read\n  contents: read\n```\n\n## Usage\n\n```\n-cache string\n      Path to JSON cache file (default \"cache.json\")\n-clean-cache\n      Reset the findings cache\n-csv string\n      Path to final CSV output file\n-end string\n      End time for workflow run filtering (RFC3339) (default \"2025-03-16T00:00:00Z\")\n-ioc-content string\n      Comma-separated string(s) to search for in logs\n-ioc-name string\n      IOC Logs to scan for (e.g. tj-actions/changed-files (default \"tj-actions/changed-files\")\n-ioc-pattern string\n      Regex pattern to search logs with\n-json string\n      Path to final JSON output file\n-start string\n      Start time for workflow run filtering (RFC3339) (default \"2025-03-14T00:00:00Z\")\n-target string\n      Organization name or owner/repository (e.g. octocat/Hello-World)\n-token string\n      GitHub Personal Access Token\n```\n\nFor example:\n```sh\n$ chainctl auth octo-sts --scope chainguard-dev/ghscan --identity ephemerality -- go run cmd/ghscan/main.go -target owner/repo -json=\"final.json\" -csv=\"final.csv\"\n2025/03/18 11:27:59 INFO Found 1 repositories to scan\n2025/03/18 11:27:59 INFO No existing cache found at cache.json, starting fresh\n```\n\nCustom IOC configuration can be provided with the flags documented above or added to `config.yaml`:\n```yaml\nioc:\n  name: \"custom-ioc-name\"\n  content: \"0e58ed8671d6b60d0890c21b07f8835ace038e67,example-string,example-string2\"\n  pattern: \"(?:^|\\\\s+)([A-Za-z0-9+/]{40,}={0,3})\"\n```\n\n`name` is a reference to the IOC\n`content` is the string or strings to search for in the Workflow logs\n`pattern` is an optional regex pattern to search for in the Workflow logs\n\nResults will be saved in the `results/` directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchainguard-dev%2Fghscan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchainguard-dev%2Fghscan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchainguard-dev%2Fghscan/lists"}