{"id":13531287,"url":"https://github.com/SpectralOps/keyscope","last_synced_at":"2025-04-01T19:31:51.144Z","repository":{"id":43888636,"uuid":"412449900","full_name":"SpectralOps/keyscope","owner":"SpectralOps","description":"Keyscope is a key and secret workflow (validation, invalidation, etc.) tool built in Rust","archived":false,"fork":false,"pushed_at":"2025-01-21T06:22:17.000Z","size":465,"stargazers_count":392,"open_issues_count":1,"forks_count":117,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-31T14:06:19.940Z","etag":null,"topics":["developer-tools","devops","pentest","rust","security","testing","vault"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/SpectralOps.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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":"2021-10-01T12:01:49.000Z","updated_at":"2025-03-25T09:49:59.000Z","dependencies_parsed_at":"2024-04-14T09:38:25.016Z","dependency_job_id":"5890c5c9-e267-4fcb-be20-08ce2e791757","html_url":"https://github.com/SpectralOps/keyscope","commit_stats":{"total_commits":49,"total_committers":6,"mean_commits":8.166666666666666,"dds":0.4285714285714286,"last_synced_commit":"50480394339872645b61c09cfa601d4e72e44bd7"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpectralOps%2Fkeyscope","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpectralOps%2Fkeyscope/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpectralOps%2Fkeyscope/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpectralOps%2Fkeyscope/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SpectralOps","download_url":"https://codeload.github.com/SpectralOps/keyscope/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246700510,"owners_count":20819888,"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":["developer-tools","devops","pentest","rust","security","testing","vault"],"created_at":"2024-08-01T07:01:01.752Z","updated_at":"2025-04-01T19:31:51.134Z","avatar_url":"https://github.com/SpectralOps.png","language":"Rust","readme":"\u003cp align=\"center\"\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n   \u003cimg src=\"media/ks.png\" width=\"420\"/\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003cb\u003e:white_check_mark: Automate your key and secret validation workflows\u003c/b\u003e\n\u003cbr/\u003e\n\u003cb\u003e:cowboy_hat_face: Over 30 different providers\u003c/b\u003e\n\u003cbr/\u003e\n\u003cb\u003e:robot: Export to JSON, audit via CSV\u003c/b\u003e\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"media/screen.png\" width=\"1019\"/\u003e\n\u003c/p\u003e\n\n# :key: Keyscope \u003cimg src=\"https://github.com/spectralops/keyscope/actions/workflows/build.yml/badge.svg\"/\u003e\n\nKeyscope is a key and secret workflow (validation, invalidation, etc.) tool built in Rust, powered by [`service_policy_kit`](https://github.com/spectralops/service-policy-kit).\n\nCurrent workflows supported:\n\n- Validation\n\n# 🦀 Why Rust?\n\n- With Rust, _\"If it compiles, it works.\"_ and also, it compiles to many platforms.\n- Rust is _fast_, has no _VM_, or unnecessary cruft (typically 5-8mb binaries with LOTS of code and libraries).\n- Multi purpose, safe, and generalistic - makes for healthy and expressive [mission critical code](https://www.youtube.com/watch?v=ylOpCXI2EMM). Adding code or abstraction doesn't increase bloat, doesn't hurt performance, doesn't increase chance for bugs in a radical way (less edge cases).\n- Amazing package manager: `Cargo`. Productive installing and running of tasks and examples.\n- Rust is getting headlines in the security community as the go-to language for security tools. Equally interesting is offensive security + Rust [here](https://github.com/trickster0/OffensiveRust) and [here](https://github.com/skerkour/black-hat-rust).\n\n# :rocket: Quick Start\n\nGrab a release from [releases](https://github.com/spectralops/keyscope/releases), or install via Homebrew:\n\n```\nbrew tap spectralops/tap \u0026\u0026 brew install keyscope\n```\n\n## Using keyscope\n\nYou can try out validating a key for a provider, say, Github (assuming the key is in the `GITHUB_TOKEN` environment variable):\n\n```\n$ keyscope validate github $GITHUB_TOKEN\n```\n\nYou can see which other providers are supported by running:\n\n```\n$ keyscope validate --list\n\n  .\n  :\n  .\n\ntwilio:validation\nkeyscope validate twilio -p twilio_1 -p twilio_2\n\ntwitter:validation\nkeyscope validate twitter -p twitter_1\n\nzendesk:validation\nkeyscope validate zendesk -p zendesk_1 -p zendesk_2\n\nTotal 44 providers available.\n$\n```\n\nAnd what parameters are required for a certain provider by running (say, `stripe`):\n\n```\n$ keyscope requirements stripe\n\nprovider stripe requires:\n - param: p1\n   desc: stripe key\n$\n```\n\nFinally the general structure of the `validate` command is:\n\n```\n$ keyscope validate PROVIDER -p PARAM1 -p PARAM2 .. -p PARAM_N\n```\n\n# :white_check_mark: Validation: key should be active\n\nYou can validate a specific provider like so:\n\n```\n$ keyscope validate twilio -p $TWILIO_KEY\n```\n\nWith the general pattern of:\n\n```\n$ keyscope validate PROVIDER -p PARAM1 -p PARAM2 ...\n```\n\nThe number of keys/params would change based on authentication type:\n\n- `Bearer` - usually just a single key (token)\n- `Basic Auth` - usually 2 keys: user, password\n- `OAuth` - usually 2 keys: client_id, client_secret\n- And others.\n\nEach provider in Keyscope will tell you what it requires using `requirements`:\n\n```\n$ keyscope requirements twilio\n```\n\nYou'll get a report:\n\n```\n$ keyscope --verbose validate stripe -p $STRIPE_KEY\n\n✔ stripe:validation: ok 766ms\n\nRan 1 interactions with 1 checks in 766ms\n\nSuccess: 1\nFailure: 0\n  Error: 0\nSkipped: 0\n```\n\nAnd an executable exit code that reflects success/failure.\n\nYou can use the `--verbose` flag to see API responses:\n\n```\n$ keyscope --verbose validate stripe -p $STRIPE_KEY\n\n✗ stripe:validation: failed 413ms\n      status_code: 200 != 401 Unauthorized\n\nRan 1 interactions with 1 checks in 413ms\n\nSuccess: 0\nFailure: 1\n  Error: 0\nSkipped: 0\n```\n\nIn this case the exit code is `1` (failure).\n\n# :x: Validation: key should be inactive\n\nWhen you are validating keys that are supposed to be inactive, you can use the `flip` flag. In this mode, a failed API access is a good thing, and the exit code will reflect that.\n\n```\n$ keyscope --flip validate stripe -p $STRIPE_KEY\n\n✔ stripe:validation: ok 766ms\n\nRan 1 interactions with 1 checks in 766ms\n```\n\nIn this case, the key is active - _which is bad for us_. Using `--flip`, the exit code will be `1` (failure).\n\n# :runner: Setting up a validation job\n\n## Audit active keys\n\nYou can set up a CI job (or other form of scheduled job you like) to perform an audit, by reading all parameters from a dedicated CSV file like so:\n\n```\n$ keyscope validate --csv-in report.csv\n```\n\nThe format of the CSV that you need to prepare should include a header line and look like this:\n\n```\nprovider,key1,key2,key3\ntwilio,tw-key1,,,\n```\n\nYou can specify as many key columns as you like, as long as you provide an _empty_ value for providers which don't have that many keys, and all rows contain the same amount of cells.\n\n## Audit inactive keys\n\nIf you have a dump of keys from your vault that are stale have expiry and should have been rotated, you want to test that they are all stale:\n\n```\n$ keyscope --flip validate --csv-in my-key-audit.csv\n```\n\n# :link: Supported providers\n\nWe're always adding [new providers](src/defs.yaml), keep a link to this list or watch this repo to get updated.\n\nWe use our [`service_policy_kit`](https://github.com/spectralops/service-policy-kit) library to specify interactions with services and their policies, if you find a service [not in this list](src/defs.yaml) feel free to open an issue or contribute back.\n\n\u003c!-- providers --\u003e\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**tester**\u003cbr/\u003eTester: valid key\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`tester_1` - hookbin ID (https://hookb.in)\u003cbr/\u003e`tester_2` - fake key to put as a query param\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate tester -p TESTER_1 -p TESTER_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**infura**\u003cbr/\u003einfura API key\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`infura_1` - infura API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate infura -p INFURA_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**covalenthq**\u003cbr/\u003eCovalent: valid key\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`covalenthq_1` - covalent token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate covalenthq -p COVALENTHQ_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**asana**\u003cbr/\u003eAsana: valid token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`asana_1` - asana token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate asana -p ASANA_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**bitly**\u003cbr/\u003eBit.ly: valid access token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`bitly_1` - bit.ly token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate bitly -p BITLY_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**ipstack**\u003cbr/\u003eipstack access key\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`ipstack_1` - ipstack access key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate ipstack -p IPSTACK_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**localytics**\u003cbr/\u003eLocalytics: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`localytics_1` - localytics user\u003cbr/\u003e`localytics_2` - localytics key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate localytics -p LOCALYTICS_1 -p LOCALYTICS_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**algolia**\u003cbr/\u003eAlgolia: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`algolia_1` - algolia application ID\u003cbr/\u003e`algolia_2` - algolia index\u003cbr/\u003e`algolia_3` - algolia API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate algolia -p ALGOLIA_1 -p ALGOLIA_2 -p ALGOLIA_3\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**branchio**\u003cbr/\u003ebranch.io: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`branchio_1` - branch.io key\u003cbr/\u003e`branchio_2` - branch.io secret\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate branchio -p BRANCHIO_1 -p BRANCHIO_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**browserstack**\u003cbr/\u003ebrowserstack: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`browserstack_1` - browserstack key\u003cbr/\u003e`browserstack_2` - browserstack secret\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate browserstack -p BROWSERSTACK_1 -p BROWSERSTACK_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**buildkite**\u003cbr/\u003eBuildkite: valid token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`buildkite_1` - buildkite token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate buildkite -p BUILDKITE_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**datadog**\u003cbr/\u003edatadog: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`datadog_1` - datadog API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate datadog -p DATADOG_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**github**\u003cbr/\u003egithub: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`github_1` - github token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate github -p GITHUB_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**github-ent**\u003cbr/\u003eGithub Enterprise: valid API token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`github-ent_1` - github enterprise instance (without http)\u003cbr/\u003e`github-ent_2` - github token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate github-ent -p GITHUB-ENT_1 -p GITHUB-ENT_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**dropbox**\u003cbr/\u003edropbox: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`dropbox_1` - dropbox token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate dropbox -p DROPBOX_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**gitlab**\u003cbr/\u003egitlab: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`gitlab_1` - gitlab token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate gitlab -p GITLAB_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**heroku**\u003cbr/\u003eheroku: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`heroku_1` - heroku token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate heroku -p HEROKU_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**mailchimp**\u003cbr/\u003emailchimp: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`mailchimp_1` - mailchimp datacenter ID\u003cbr/\u003e`mailchimp_2` - mailchimp key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate mailchimp -p MAILCHIMP_1 -p MAILCHIMP_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**mailgun**\u003cbr/\u003emailgun: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`mailgun_1` - mailgun key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate mailgun -p MAILGUN_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**pagerduty**\u003cbr/\u003epagerduty: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`pagerduty_1` - pagerduty token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate pagerduty -p PAGERDUTY_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**circleci**\u003cbr/\u003ecircleci: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`circleci_1` - circleci key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate circleci -p CIRCLECI_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**facebook-access-token**\u003cbr/\u003efacebook: valid API token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`facebook-access-token_1` - facebook token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate facebook-access-token -p FACEBOOK-ACCESS-TOKEN_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**salesforce**\u003cbr/\u003esalesforce: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`salesforce_1` - salesforce instance name\u003cbr/\u003e`salesforce_2` - salesforce token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate salesforce -p SALESFORCE_1 -p SALESFORCE_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**jumpcloud**\u003cbr/\u003ejumpcloud: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`jumpcloud_1` - jumpcloud key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate jumpcloud -p JUMPCLOUD_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**saucelabs-us**\u003cbr/\u003esaucelabs-us: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`saucelabs-us_1` - saucelabs user\u003cbr/\u003e`saucelabs-us_2` - saucelabs key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate saucelabs-us -p SAUCELABS-US_1 -p SAUCELABS-US_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**saucelabs-eu**\u003cbr/\u003esaucelabs-eu: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`saucelabs-eu_1` - saucelabs user\u003cbr/\u003e`saucelabs-eu_2` - saucelabs key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate saucelabs-eu -p SAUCELABS-EU_1 -p SAUCELABS-EU_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**sendgrid**\u003cbr/\u003esendgrid: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`sendgrid_1` - sendgrid key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate sendgrid -p SENDGRID_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**slack**\u003cbr/\u003eslack: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`slack_1` - slack key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate slack -p SLACK_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**slack-webhook**\u003cbr/\u003eslack-webook: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`slack-webhook_1` - slack webhook\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate slack-webhook -p SLACK-WEBHOOK_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**stripe**\u003cbr/\u003estripe: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`stripe_1` - stripe key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate stripe -p STRIPE_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**travisci**\u003cbr/\u003etravisci: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`travisci_1` - travisci domain, choose 'org' or 'com'\u003cbr/\u003e`travisci_2` - travisci key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate travisci -p TRAVISCI_1 -p TRAVISCI_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**twilio**\u003cbr/\u003etwilio: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`twilio_1` - twilio account sid\u003cbr/\u003e`twilio_2` - twilio token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate twilio -p TWILIO_1 -p TWILIO_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**twitter**\u003cbr/\u003etwitter: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`twitter_1` - twitter API token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate twitter -p TWITTER_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**zendesk**\u003cbr/\u003ezendesk: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`zendesk_1` - zendesk domain\u003cbr/\u003e`zendesk_2` - zendesk key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate zendesk -p ZENDESK_1 -p ZENDESK_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**firebase**\u003cbr/\u003efirebase: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`firebase_1` - firebase API key\u003cbr/\u003e`firebase_2` - firebase ID token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate firebase -p FIREBASE_1 -p FIREBASE_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**aws**\u003cbr/\u003eaws: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`aws_1` - AWS ID\u003cbr/\u003e`aws_2` - AWS secret\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate aws -p AWS_1 -p AWS_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**elastic-apm-secret**\u003cbr/\u003eElastic APM: secret key validation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`elastic-apm-secret_1` - Elastic APM host address and port, including 'http/s' part\u003cbr/\u003e`elastic-apm-secret_2` - Elastic APM secret\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate elastic-apm-secret -p ELASTIC-APM-SECRET_1 -p ELASTIC-APM-SECRET_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**artifactory**\u003cbr/\u003eArtifactory: token validation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`artifactory_1` - Artifactory host (including http(s) part)\u003cbr/\u003e`artifactory_2` - Artifactory token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate artifactory -p ARTIFACTORY_1 -p ARTIFACTORY_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**ibm-cos**\u003cbr/\u003eIBM: cloud object storage key validation (HMAC)\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`ibm-cos_1` - IBM HMAC ID\u003cbr/\u003e`ibm-cos_2` - IBM HMAC secret\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate ibm-cos -p IBM-COS_1 -p IBM-COS_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**ibm-iam**\u003cbr/\u003eIBM: cloud key validation (IAM)\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`ibm-iam_1` - IBM cloud key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate ibm-iam -p IBM-IAM_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**ibm-cloudant**\u003cbr/\u003eIBM: cloudant key validation (legacy)\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`ibm-cloudant_1` - IBM cloudant hostname\u003cbr/\u003e`ibm-cloudant_2` - IBM cloudant user\u003cbr/\u003e`ibm-cloudant_3` - IBM cloudant key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate ibm-cloudant -p IBM-CLOUDANT_1 -p IBM-CLOUDANT_2 -p IBM-CLOUDANT_3\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**softlayer**\u003cbr/\u003eSoftlayer: validate credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`softlayer_1` - Softlayer hostname\u003cbr/\u003e`softlayer_2` - Softlayer token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate softlayer -p SOFTLAYER_1 -p SOFTLAYER_2\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**square**\u003cbr/\u003eSquare: valid token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`square_1` - Square token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate square -p SQUARE_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**telegram-bot**\u003cbr/\u003etelegram-bot: valid bot token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`telegram-bot_1` - bot key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate telegram-bot -p TELEGRAM-BOT_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**bingmaps**\u003cbr/\u003eBing Maps API: valid access token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`bingmaps_1` - Bing Maps token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate bingmaps -p BINGMAPS_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**buttercms**\u003cbr/\u003eButterCMS: valid bot token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`buttercms_1` - ButterCMS API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate buttercms -p BUTTERCMS_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**wakatime**\u003cbr/\u003ewakatime: valid api token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`wakatime_1` - WakeTime API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate wakatime -p WAKATIME_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**calendly**\u003cbr/\u003ecalendly: valid API credentials\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`calendly_1` - calendly API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate calendly -p CALENDLY_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**shodan**\u003cbr/\u003eshodan: valid api token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`shodan_1` - Shodan API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate shodan -p SHODAN_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**opsgenie**\u003cbr/\u003eopsgenie: valid api token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`opsgenie_1` - opsgenie API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate opsgenie -p OPSGENIE_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**pendo**\u003cbr/\u003ependo: valid api token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`pendo_1` - pendo API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate pendo -p PENDO_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**hubspot**\u003cbr/\u003ehubspot: valid api token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`hubspot_1` - hubspot API key\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate hubspot -p HUBSPOT_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**lokalise**\u003cbr/\u003elokalise: valid api token\n\n\u003c/td\u003e\n\u003ctd\u003e\n\nvalidation\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n`lokalise_1` - lokalise token\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd colspan=\"3\"\u003e\n\n```\nkeyscope validate lokalise -p LOKALISE_1\n```\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\u003c!-- /providers --\u003e\n\n# :cake: Adding your own providers\n\nYou can specify a custom definitions file (here [is an example](custom-defs.example.yaml)):\n\n```\n$ keyscope -f your-definitions.yaml validate --list\n```\n\nWhich is suitable for adding your own internal services, key issuing policies, and infrastructure.\n\nYou can also use custom definitions to test out new providers that you'd like to contribute back to keyscope :smile:\n\n## Basics of a definition\n\nAll definitions represent an interaction. A request being made, and a policy that's being checked against it.\n\n```yaml\nproviders:\n  hookbin:\n    validation:\n      #\n      # the request part\n      #\n      request:\n        params:\n          - name: hookbin_1\n            desc: hookbin ID (https://hookb.in)\n          - name: hookbin_2\n            desc: fake key to put as a query param\n        id: \"postbin:validation\"\n        desc: \"Postbin: valid key\"\n        # variable interpolation is good for all fields\n        uri: \"https://hookb.in/{{hookbin_1}}?q={{hookbin_2}}\"\n        method: post\n        # you can also use headers, body, form, basic_auth and more (see defs.yaml)\n\n      #\n      # the policy part: all values are actually regular expressions and are matched against service response\n      #\n      response:\n        status_code: \"200\"\n        body: ok\n```\n\nWhen in doubt, you can check keyscope's own [defs.yaml](src/defs.yaml) for real examples of how to use this infrastructure.\n\n## Tutorial: adding Dropbox\n\nTo validate if a dropbox API key works, we first need to learn about the canonical way to authenticate against that API.\n\nFirst stop, API docs:\n\n- Dropbox has an [API Explorer](https://dropbox.github.io/dropbox-api-v2-explorer) which is super useful\n\nNext stop, we want to find an API call that is a representative for:\n\n- Has to be authenticated\n- Has to indicate that when accessed successfully with our candidate key, the key has some authoritative value. Which means, that if exposed, contains significant risk.\n\nFor this example, getting our current account sounds like something that only when we identify who we are - we're able to do.\n\nWe'll select [get_current_account](https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account).\n\nLet's start forming our interaction. First the needed skeleton: containing the name of the provider (`dropbox`), its ID and description below, as well as parameters required and their name and description:\n\n```yaml\ndropbox:\n  validation:\n    request:\n      id: \"dropbox:validation\"\n      desc: \"dropbox: valid API credentials\"\n      params:\n        - name: dropbox_1\n          desc: dropbox token\n```\n\nWe keep the name of the parameter with a special convention that helps when feeding keyscope automatically:\n\n```\nPROVIDER_N\nWhere 'N' starts in 1 e.g.:\ndropbox_1\ndropbox_2\naws_1\n...\n```\n\nThen, details about actually making an HTTP call, as required by Dropbox (Bearer token authentication).\n\n```yaml\nuri: https://api.dropboxapi.com/2/users/get_current_account\nmethod: post\nheaders:\n  Authorization:\n    - Bearer {{dropbox_1}}\n```\n\nNote that per standard, all HTTP header fields are actually _arrays_. It's OK to always make an array of size _one_ if you only have one value (most common case).\n\nWe also see _variable interpolation_ here. Where `{{dropbox_1}}` will get replaced by keyscope in time before making the actual call.\n\nFinally, we want to make sure we answer the question:\n\n- What does it mean to have a successful call?\n\nIn our case, the Dropbox API call returns `HTTP OK` on success, which means a `200` status code.\n\nAnd the final, complete result is this:\n\n```yaml\ndropbox:\n  validation:\n    request:\n      id: \"dropbox:validation\"\n      desc: \"dropbox: valid API credentials\"\n      params:\n        - name: dropbox_1\n          desc: dropbox token\n      uri: https://api.dropboxapi.com/2/users/get_current_account\n      method: post\n      headers:\n        Authorization:\n          - Bearer {{dropbox_1}}\n    response:\n      status_code: \"200\"\n```\n\nMeanwhile, you can drop this provider in your own `providers.yaml` file and run keyscope:\n\n```\n$ keyscope -f providers.yaml validate dropbox -p MY_KEY\n```\n\nNow you can keep this in your private `providers.yaml` file or contribute it back to keyscope if you think other people might enjoy using it - we're happy to accept pull requests.\n\n# Thanks\n\nTo all [Contributors](https://github.com/spectralops/keyscope/graphs/contributors) - you make this happen, thanks!\n\n# Copyright\n\nCopyright (c) 2021 [@jondot](http://twitter.com/jondot). See [LICENSE](LICENSE.txt) for further details.\n","funding_links":[],"categories":["Tools","Open Sources Intelligence (OSINT)","Web","Rust","Application Security","2. [↑](#-content) Pentesting"],"sub_categories":["Binary files examination and editing","Penetration Testing Report Templates","Scanning / Pentesting","Secrets Management","Secrets detection","2.5 [↑](#-content) Web","Web Vulnerability Scanners"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSpectralOps%2Fkeyscope","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSpectralOps%2Fkeyscope","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSpectralOps%2Fkeyscope/lists"}