{"record":{"id":"42bea0f4d9d976bc","repo":"wpscanteam/wpscan","slug":"api-token-and-enterprise-db-token-are-mutually","errorCode":null,"errorMessage":"--api-token and --enterprise-db-token are mutually exclusive, please provide only one (this also applies to the WPSCAN_API_TOKEN and WPSCAN_ENTERPRISE_DB_TOKEN environment variables).","messagePattern":"--api-token and --enterprise-db-token are mutually exclusive, please provide only one \\(this also applies to the WPSCAN_API_TOKEN and WPSCAN_ENTERPRISE_DB_TOKEN environment variables\\)\\.","errorType":"exception","errorClass":"WPScan::Error::ConflictingApiTokens","httpStatus":null,"severity":"error","filePath":"app/controllers/vuln_api.rb","lineNumber":26,"sourceCode":"      ENTERPRISE_ENV_KEY = 'WPSCAN_ENTERPRISE_DB_TOKEN'\n\n      # Class level so that Controller::Core (which runs first) can validate the tokens right after\n      # the CLI options have been parsed, aborting before anything else (DB update, requests to the\n      # target) is done.\n      class << self\n        # @return [ String, nil ] The enterprise DB token (CLI or ENV). Must match DB::Updater's resolution.\n        def enterprise_db_token\n          ParsedCli.enterprise_db_token || ENV.fetch(ENTERPRISE_ENV_KEY, nil)\n        end\n\n        # @return [ String, nil ] The API token (CLI or ENV var)\n        def api_token\n          ParsedCli.api_token || ENV.fetch(ENV_KEY, nil)\n        end\n\n        # @raise [ Error::ConflictingApiTokens ] When both the API and enterprise DB tokens are supplied\n        def validate_api_tokens!\n          raise Error::ConflictingApiTokens if enterprise_db_token && api_token\n        end\n      end\n\n      def cli_options\n        [\n          OptString.new(\n            ['--api-token TOKEN',\n             'The WPScan API Token to display vulnerability data, available at https://wpscan.com/profile']\n          ),\n          OptString.new(\n            ['--enterprise-db-token TOKEN',\n             'Use a local enterprise vulnerability database dump instead of the WPScan API. The ' \\\n             'plugins/themes/wordpresses dumps are downloaded from enterprise-data.wpscan.org using ' \\\n             'this token during the database update, then read locally (no per-finding API calls). Mutually ' \\\n             \"exclusive with --api-token. Can also be set via the #{ENTERPRISE_ENV_KEY} environment variable.\"],\n            { advanced: true }\n          ),\n          OptBoolean.new(","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/wpscanteam/wpscan/blob/62c9cef471de90095f6b42245a11d0f8172d19c9/app/controllers/vuln_api.rb#L8-L44","documentation":"Raised by VulnApi.validate_api_tokens! (app/controllers/vuln_api.rb:26), invoked from Core#before_scan before any request is sent. It fires when both an API token and an enterprise DB token resolve at the same time — via --api-token/--enterprise-db-token flags, the WPSCAN_API_TOKEN/WPSCAN_ENTERPRISE_DB_TOKEN environment variables, or config files. The two tokens select mutually exclusive vulnerability-data backends (cloud API vs local enterprise dumps), so supplying both is rejected early.","triggerScenarios":"Any run where `ParsedCli.enterprise_db_token || ENV['WPSCAN_ENTERPRISE_DB_TOKEN']` and `ParsedCli.api_token || ENV['WPSCAN_API_TOKEN']` are both truthy — e.g. a CI pipeline exporting WPSCAN_API_TOKEN globally while the command also passes --enterprise-db-token.","commonSituations":"Shared CI runners carrying stale WPSCAN_* env vars; migration from the cloud API to the enterprise DB without unsetting the old variable; both keys present in ~/.config/wpscan/scan.yml plus an env var; copy-pasting an enterprise command into a shell that already exports WPSCAN_API_TOKEN.","solutions":["Keep exactly one source: remove either --api-token or --enterprise-db-token from the command","Check the environment: env | grep -i wpscan, then unset WPSCAN_API_TOKEN or unset WPSCAN_ENTERPRISE_DB_TOKEN","Inspect config files (~/.config/wpscan/scan.{yml,json}, ./.wpscan/scan.{yml,json}) for api_token/enterprise_db_token keys and delete the extra one"],"exampleFix":"# before\nWPSCAN_API_TOKEN=xxx wpscan --url http://t --enterprise-db-token yyy\n# => --api-token and --enterprise-db-token are mutually exclusive ...\n\n# after\nunset WPSCAN_API_TOKEN\nwpscan --url http://t --enterprise-db-token yyy","handlingStrategy":"validation","validationCode":"# Assert token exclusivity before launching WPScan\napi = ARGV.grep(/--api-token/) + [ENV['WPSCAN_API_TOKEN']].compact\nent = ARGV.grep(/--enterprise-db-token/) + [ENV['WPSCAN_ENTERPRISE_DB_TOKEN']].compact\nabort 'pick exactly one token source' if api.any? && ent.any?\n# or from Ruby: WPScan::Controller::VulnApi.validate_api_tokens!","typeGuard":null,"tryCatchPattern":"begin\n  WPScan::Controller::VulnApi.validate_api_tokens!\nrescue WPScan::Error::ConflictingApiTokens\n  ENV.delete('WPSCAN_API_TOKEN') # or drop the offending flag, then retry\n  retry\nend","preventionTips":["Set only one of the two tokens in CI variables","Scope WPSCAN_* env vars per project to avoid leaking global values","Document in runbooks that the tokens are mutually exclusive","Pre-validate tokens — WPScan is designed to fail fast here"],"tags":["configuration","api-token","cli-options","environment-variables","mutually-exclusive"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"62c9cef471de90095f6b42245a11d0f8172d19c9","analyzedAt":"2026-08-21T17:10:47.902Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}