diff --git a/benchmarks/valid/train/CANDIDATES_access_control.md b/benchmarks/valid/train/CANDIDATES_access_control.md new file mode 100644 index 0000000..6078c16 --- /dev/null +++ b/benchmarks/valid/train/CANDIDATES_access_control.md @@ -0,0 +1,324 @@ +# Training-set candidates for the maintainer's spot-check + +Generated 2026-10-13 by `benchmarks/valid/train/sourcing.py candidates`. Every location below passed all three +model checks (vulnerable before the fix, fix addresses it, reachable from an in-repo entry point) and waits for a +human accept or reject. Nothing here is a positive until accepted. Accept or reject a location with + + .venv/bin/python -m benchmarks.valid.verify spot-check benchmarks/valid/train/verification.json accept|reject --reviewer --date YYYY-MM-DD + +Sites passing: 69 in 27 repositories, 27 positive changes (fix commits); languages: java 63, javascript 2, php 2, python 1, typescript 1 + +The verifier's entry point is the model's claim, not a checked fact; it is the reason the site passed the reachability check. + +## apache/seatunnel + +- advisory: GHSA-9x53-gr7p-4qf5 (access_control, CWE-306), origin `?`, ecosystem ?, licence ? +- fix `53325aa3e76e3939f41a4bf3eaaf3ee56f13f311`, parent (fix^1) `8a9db476bdc37d5e4079491bdb7092b892a17a7b` +- advisory title: Apache SeaTunnel: Unauthenticated insecure access + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `apache-seatunnel-aff20b2911a11f57` | `seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/JettyService.java::JettyService` (88-100) | java | /hazelcast/rest/maps/submit-job (SubmitJobServlet) via JettyService.createJettyServer | 0.75 | + +## friendsofflarum/byobu + +- advisory: GHSA-6gjm-6wj6-4px5 (access_control, CWE-863), origin `?`, ecosystem ?, licence ? +- fix `23dcf93a30f948d30c678a96681f7fdefeba5171`, parent (fix^1) `2e99cdb7e356a259ea90aa7f84a71fc0f050e006` +- advisory title: Byobu user preference to prevent private discussions being started are not respected + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `friendsofflarum-byobu-7173b8a509cf3e27` | `js/src/forum/extend/User.js::extend` (19-62) | javascript | UserControls 'userControls' extension rendering the private-discussion button on a user's profile page; source is the target user's blocksPd/cannotBeDirectMessaged attributes | 0.75 | +| `friendsofflarum-byobu-f34c4fa78b9178db` | `js/src/forum/pages/PrivateDiscussionsUserPage.js::actionItems` (55-66) | javascript | PrivateDiscussionsUserPage.actionItems rendered via content() on the user private discussions page route (m.route.param('username')) | 0.75 | + +## jenkinsci/analysis-core-plugin + +- advisory: GHSA-vvfj-p4jf-j8rm (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `3d7a0c7907d831c58541508b893dcea2039809c5`, parent (fix^1) `892ab94f85a49d8c04b302c9bf48b112efe97536` +- advisory title: Missing permission check in Jenkins Static Analysis Utilities Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-analysis-core-plugin-e02e86e3c18ec1d6` | `src/main/java/hudson/plugins/analysis/graph/DefaultGraphConfigurationView.java::persistValue` (126-136) | java | DefaultGraphConfigurationView#doSave form handler (configureDefaults URL) via StaplerRequest | 0.85 | + +## jenkinsci/azure-credentials-plugin + +- advisory: GHSA-7j55-28qq-676g (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `64da8176c83a41bb83d3ad759628c9bd275b42f5`, parent (fix^1) `887e0f9e898b2765d78e53c7b39017b8d6295dca` +- advisory title: Missing Authorization in Jenkins Azure Credentials Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-azure-credentials-plugin-0dab78b4ed2c29bb` | `src/main/java/com/microsoft/jenkins/keyvault/SecretStringCredentials.java::doVerifyConfiguration` (46-64) | java | Jenkins Stapler HTTP endpoint /descriptorByName/com.microsoft.jenkins.keyvault.SecretStringCredentials/doVerifyConfiguration (doVerifyConfiguration in DescriptorImpl), invoked via web request with ser | 0.85 | +| `jenkinsci-azure-credentials-plugin-144d42edd4fea476` | `src/main/java/com/microsoft/jenkins/keyvault/BaseSecretCredentials.java::doFillServicePrincipalIdItems` (97-103) | java | Jenkins Stapler web endpoint doFillServicePrincipalIdItems on the Azure Credentials DescriptorImpl (form fill for servicePrincipalId), reachable by any user with Overall/Read permission | 0.85 | +| `jenkinsci-azure-credentials-plugin-81c51344b9d31af8` | `src/main/java/com/microsoft/azure/util/AzureCredentials.java::doVerifyConfiguration` (772-800) | java | Jenkins Stapler HTTP endpoint doVerifyConfiguration on AzureCredentials.DescriptorImpl, invoked via form validation request with query parameters (subscriptionId, clientId, clientSecret, etc.) | 0.85 | +| `jenkinsci-azure-credentials-plugin-a83f939fb055e6a0` | `src/main/java/com/microsoft/azure/util/AzureCredentials.java::doFillCertificateIdItems` (802-808) | java | Jenkins Stapler web method doFillCertificateIdItems on AzureCredentials.DescriptorImpl, invoked via the credentials configuration form (e.g. /descriptorByName/com.microsoft.azure.util.AzureCredentials | 0.85 | +| `jenkinsci-azure-credentials-plugin-af7645f7ae48e24c` | `src/main/java/com/microsoft/jenkins/keyvault/SecretCertificateCredentials.java::doVerifyConfiguration` (105-134) | java | Jenkins Stapler HTTP endpoint DescriptorImpl.doVerifyConfiguration (form validation endpoint) invoked via web request with @QueryParameter servicePrincipalId/secretIdentifier/password | 0.85 | +| `jenkinsci-azure-credentials-plugin-bd1228731e6d22aa` | `src/main/java/com/microsoft/azure/util/AzureImdsCredentials.java::validate` (55-94) | java | DescriptorImpl.doVerifyConfiguration (@POST, @QueryParameter subscriptionId/clientId/azureEnvironmentName) | 0.75 | +| `jenkinsci-azure-credentials-plugin-d3c1129ce0199756` | `src/main/java/com/microsoft/azure/util/AzureImdsCredentials.java::doVerifyConfiguration` (107-128) | java | Jenkins DescriptorImpl.doVerifyConfiguration (AzureImdsCredentials) exposed via Stapler HTTP endpoint /descriptorByName/.../doVerifyConfiguration with @QueryParameter subscriptionId, clientId, azureEn | 0.85 | + +## jenkinsci/azure-keyvault-plugin + +- advisory: GHSA-gf8w-6hcm-rh3j (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `f09ed652cc572d8ba5d7c8c8f9972fd241883c21`, parent (fix^1) `36680c54a27685d6d35d75135daa6e386a107a1b` +- advisory title: Missing permission checks in Jenkins Azure Key Vault Plugin allow enumerating credentials IDs + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-azure-keyvault-plugin-a9975f6d8b4f1568` | `src/main/java/org/jenkinsci/plugins/azurekeyvaultplugin/AzureKeyVaultBuildWrapper.java::SuppressWarnings` (290-295) | java | Jenkins Stapler HTTP endpoint doFillCredentialIDOverrideItems on AzureKeyVaultBuildWrapper.DescriptorImpl (form fill for credentialIDOverride field), reachable by any user with Overall/Read permission | 0.85 | +| `jenkinsci-azure-keyvault-plugin-abd182ce20617255` | `src/main/java/org/jenkinsci/plugins/azurekeyvaultplugin/AzureKeyVaultStep.java::SuppressWarnings` (218-223) | java | DescriptorImpl.doFillCredentialIDItems (Jenkins Stapler HTTP endpoint /job/.../descriptorByName/.../fillCredentialIDItems) | 0.75 | + +## jenkinsci/blueocean-plugin + +- advisory: GHSA-vc7g-4269-f7hw (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `659a66aff0d0ad693eab9d2807985d591e102aab`, parent (fix^1) `966da5a824c0e78767ba8b6a40be2ebfd8d8919f` +- advisory title: Missing permission check in Blue Ocean Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-blueocean-plugin-5aa4f2eb0a53ebfe` | `blueocean-github-pipeline/src/main/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubServerContainer.java::create` (56-145) | java | GithubServerContainer.create(@JsonBody JSONObject request) invoked via Blue Ocean HTTP endpoint for creating GitHub server; attacker-controlled source is the 'apiUrl' field in the JSON request body, w | 0.85 | +| `jenkinsci-blueocean-plugin-e4ad2dadd845ec00` | `blueocean-bitbucket-pipeline/src/main/java/io/jenkins/blueocean/blueocean_bitbucket_pipeline/server/BitbucketServerEndpointContainer.java::create` (44-97) | java | Blue Ocean REST endpoint POST /blueocean/rest/.../servers (ScmServerEndpointContainer.create) accepting JSONObject request with attacker-controlled API_URL | 0.75 | + +## jenkinsci/compuware-scm-downloader-plugin + +- advisory: GHSA-75fc-fv3p-xh82 (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `bf00665b13641351a9f67027bbe34609cc4f65e2`, parent (fix^1) `115f057078baad506e2b34b74f4f0600f81990b3` +- advisory title: Jenkins Compuware Source Code Download is missing authorization + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-compuware-scm-downloader-plugin-29636a1534a39217` | `src/main/java/com/compuware/jenkins/scm/PdsConfiguration.java::doFillConnectionIdItems` (254-276) | java | Jenkins Stapler HTTP endpoint doFillConnectionIdItems (e.g. /job//descriptorByName/.../fillConnectionIdItems) invoked via config.jelly connectionId field; attacker-controlled source is the HTTP | 0.85 | +| `jenkinsci-compuware-scm-downloader-plugin-316557e9fdf67223` | `src/main/java/com/compuware/jenkins/scm/IspwContainerConfiguration.java::doFillConnectionIdItems` (312-334) | java | Jenkins Stapler HTTP endpoint doFillConnectionIdItems (e.g. /job//descriptorByName/.../fillConnectionIdItems) invoked via config.jelly connectionId field; attacker-controlled source is the HTTP | 0.85 | +| `jenkinsci-compuware-scm-downloader-plugin-4b64810cb01a07f5` | `src/main/java/com/compuware/jenkins/scm/AbstractConfiguration.java::doFillCredentialsIdItems` (107-131) | java | Jenkins Stapler HTTP endpoint doFillCredentialsIdItems (e.g. /job//descriptorByName/.../fillCredentialsIdItems) invoked with Overall/Read permission; attacker-controlled source is the credential | 0.85 | +| `jenkinsci-compuware-scm-downloader-plugin-936a096a4a941ee5` | `src/main/java/com/compuware/jenkins/scm/EndevorConfiguration.java::doFillConnectionIdItems` (255-277) | java | Jenkins Stapler HTTP endpoint doFillConnectionIdItems (e.g. /job//descriptorByName/.../fillConnectionIdItems) invoked via config.jelly connectionId field; attacker-controlled source is the HTTP | 0.85 | +| `jenkinsci-compuware-scm-downloader-plugin-c416a32628e63296` | `src/main/java/com/compuware/jenkins/scm/IspwConfiguration.java::doFillConnectionIdItems` (416-438) | java | Jenkins Stapler HTTP endpoint doFillConnectionIdItems (e.g. /job//descriptorByName/.../fillConnectionIdItems) invoked via @QueryParameter connectionId | 0.85 | + +## jenkinsci/compuware-topaz-for-total-test-plugin + +- advisory: GHSA-x5gv-5rqv-654m (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `0ba4274d545eac39e3db48b5dfb4512db3242946`, parent (fix^1) `5fca6eb21599f8f27323dfa17a6e44f8176ca551` +- advisory title: Jenkins Compuware Topaz for Total Test Plugin allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-compuware-topaz-for-total-test-plugin-0fcc9e440100be20` | `src/main/java/com/compuware/jenkins/totaltest/TotalTestBuilder.java::doFillCredentialsIdItems` (857-889) | java | Jenkins Stapler HTTP endpoint doFillCredentialsIdItems (descriptor form fill for credentialsId), reachable via Overall/Read authenticated user; source is the credentialsId query parameter and the cred | 0.85 | +| `jenkinsci-compuware-topaz-for-total-test-plugin-31007615cf224711` | `src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java::doFillConnectionIdItems` (1534-1556) | java | Jenkins Stapler HTTP endpoint doFillConnectionIdItems (e.g. /job//descriptorByName/.../fillConnectionIdItems) invoked with Overall/Read permission; @QueryParameter connectionId is attacker-contr | 0.85 | +| `jenkinsci-compuware-topaz-for-total-test-plugin-3b2dc3167c986714` | `src/main/java/com/compuware/jenkins/totaltest/TotalTestBuilder.java::doFillConnectionIdItems` (798-820) | java | Jenkins Stapler HTTP endpoint doFillConnectionIdItems (e.g. /job//descriptorByName/.../fillConnectionIdItems) invoked via @QueryParameter connectionId | 0.85 | +| `jenkinsci-compuware-topaz-for-total-test-plugin-8659f27b971d364f` | `src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java::doFillCredentialsIdItems` (1644-1670) | java | Jenkins Stapler HTTP endpoint doFillCredentialsIdItems on TotalTestCTBuilder (e.g. /job//descriptorByName/.../fillCredentialsIdItems), invoked via @QueryParameter credentialsId with Overall/Read | 0.85 | +| `jenkinsci-compuware-topaz-for-total-test-plugin-b0ca3df515237e75` | `src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java::doFillServerUrlItems` (1681-1773) | java | Jenkins Stapler HTTP endpoint doFillServerUrlItems / doFillServerCredentialsIdItems (form fill methods invoked via Jenkins UI/HTTP request with Overall/Read permission) | 0.85 | +| `jenkinsci-compuware-topaz-for-total-test-plugin-e724ca5f96b58ee5` | `src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java::doFillServerCredentialsIdItems` (1740-1766) | java | Jenkins Stapler HTTP endpoint doFillServerCredentialsIdItems (descriptor form fill method) reachable via the build step configuration UI; attacker-controlled source is the @QueryParameter serverCreden | 0.85 | + +## jenkinsci/conjur-credentials-plugin + +- advisory: GHSA-372f-jc47-7gr5 (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `eda06cde26cdf2d40ae4e2f4d2709e8174489068`, parent (fix^1) `811b0672d5a88d2145823f7355619ddd5f328e17` +- advisory title: Missing permission check in Jenkins Conjur Secrets Plugin allows enumerating credentials IDs + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-conjur-credentials-plugin-11205c0022207637` | `src/main/java/org/conjur/jenkins/conjursecrets/ConjurSecretCredentialsDescriptor.java::doFillCredentialIDItems` (22-27) | java | Jenkins Stapler HTTP endpoint doFillCredentialIDItems (form fill for credential ID field), invoked via web request with uri query parameter | 0.75 | +| `jenkinsci-conjur-credentials-plugin-25bfc860016819fb` | `src/main/java/org/conjur/jenkins/conjursecrets/ConjurSecretUsernameSSHKeyCredentialsImpl.java::doFillCredentialIDItems` (98-104) | java | Jenkins Stapler HTTP endpoint doFillCredentialIDItems on ConjurSecretUsernameSSHKeyCredentialsImpl.DescriptorImpl, invoked via the credentials form fill (e.g. credentialID field) with @QueryParameter | 0.85 | +| `jenkinsci-conjur-credentials-plugin-f42fa606284883ea` | `src/main/java/org/conjur/jenkins/conjursecrets/ConjurSecretUsernameCredentialsImpl.java::doFillCredentialIDItems` (96-103) | java | Jenkins Stapler HTTP endpoint doFillCredentialIDItems on ConjurSecretUsernameCredentialsImpl.DescriptorImpl, invoked via the credentials form fill (e.g. /descriptorByName/.../fillCredentialIDItems) wi | 0.85 | + +## jenkinsci/crx-content-package-deployer-plugin + +- advisory: GHSA-4cmq-88f8-53r5 (access_control, CWE-285), origin `?`, ecosystem ?, licence ? +- fix `06cd0e7e1b3f2fb87b3fa332ee1da710ca94b8e1`, parent (fix^1) `1313c422170a064dab0f9359324ff27e30a9f4a5` +- advisory title: Jenkins CRX Content Package Deployer Plugin subject to credentials enumeration via Missing Authorization + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-crx-content-package-deployer-plugin-79286d969348bd3c` | `src/main/java/org/jenkinsci/plugins/graniteclient/GraniteAHCFactory.java::doFillCredentialsIdItems` (149-153) | java | Jenkins Stapler HTTP endpoint /descriptor/.../fillCredentialsIdItems (doFillCredentialsIdItems) invoked via form binding with @QueryParameter value | 0.85 | + +## jenkinsci/database-plugin + +- advisory: GHSA-hj36-v72x-cc6j (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `7a438d96897af0034cb2e06db0819ca4595c24cb`, parent (fix^1) `a68258cf17ba8d5264010cc760770a62a3cc6c2d` +- advisory title: Missing permission checks in Jenkins Database Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-database-plugin-6a8e141d0c9eaab2` | `src/main/java/org/jenkinsci/plugins/database/AbstractRemoteDatabaseDescriptor.java::doValidate` (24-42) | java | Stapler form validation endpoint doValidate on AbstractRemoteDatabaseDescriptor (e.g. /descriptorByName/.../validate) invoked via HTTP with @QueryParameter hostname, database, username, password, prop | 0.85 | +| `jenkinsci-database-plugin-d2e038dce743f4f4` | `src/main/java/org/jenkinsci/plugins/database/GenericDatabase.java::doCheckDriver` (85-110) | java | Jenkins form validation endpoint /descriptorByName/org.jenkinsci.plugins.database.GenericDatabase/doValidate (and doCheckDriver), invoked via HTTP with attacker-controlled driver, url, username, passw | 0.85 | +| `jenkinsci-database-plugin-fdb5a7fd01260ec1` | `src/main/java/org/jenkinsci/plugins/database/GenericDatabase.java::doValidate` (97-108) | java | Jenkins form validation endpoint doValidate (Descriptor.doValidate) invoked via HTTP POST with query parameters driver, url, username, password | 0.85 | + +## jenkinsci/deployer-framework-plugin + +- advisory: GHSA-rqqx-fvqx-539g (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `7ba4a55bf3ec567ee5325ea7b24b4086ac1cb3ad`, parent (fix^1) `1d1888e8c0214fa42ee932b3eb26c06a6c7279f0` +- advisory title: Jenkins Deployer Framework Plugin allows attackers with Item/Read permission to read deployment logs + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-deployer-framework-plugin-2929f3e176f304ad` | `src/main/java/com/cloudbees/plugins/deployer/sources/FixedDirectoryDeploySource.java::SuppressWarnings` (195-222) | java | Stapler HTTP endpoint doCheckDirectoryPath (FormValidation) on FixedDirectoryDeploySource.DescriptorImpl, invoked via @QueryParameter fromWorkspace/targetDescriptorId/value | 0.6 | +| `jenkinsci-deployer-framework-plugin-dd5ef66a767e04d5` | `src/main/java/com/cloudbees/plugins/deployer/DeployNowRunAction.java::doDeployText` (361-384) | java | Stapler HTTP endpoint doDeployText (DeployNowRunAction) reachable via URL /job///deploy-text or similar Stapler route; attacker-controlled source is the HTTP request handled by StaplerRequ | 0.85 | + +## jenkinsci/ec2-plugin + +- advisory: GHSA-6hmm-77r2-h6hr (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `0cdbaf2d7da5c368209f427559c8608dec22a63b`, parent (fix^1) `2af0a6da84ef203c463981afbd81da0c0b1b5364` +- advisory title: Missing permission checks in Jenkins Amazon EC2 Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-ec2-plugin-6058527110940076` | `src/main/java/hudson/plugins/ec2/EC2Cloud.java::doTestConnection` (934-959) | java | Jenkins Stapler form validation endpoint doTestConnection on EC2Cloud.DescriptorImpl, invoked via HTTP form validation request with attacker-controlled ec2endpoint, credentialsId, roleArn, roleSession | 0.85 | +| `jenkinsci-ec2-plugin-92278d8bf0b7f60a` | `src/main/java/hudson/plugins/ec2/EC2Cloud.java::doGenerateKey` (960-991) | java | Jenkins Stapler form validation endpoint /descriptorByName/hudson.plugins.ec2.EC2Cloud/doGenerateKey (and doTestConnection), invoked via HTTP with attacker-controlled ec2EndpointUrl, credentialsId, re | 0.85 | + +## jenkinsci/electricflow-plugin + +- advisory: GHSA-7rx6-4vwv-432g (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `597cbb1d767ae92c44b4cbd9525fa53ddab37117`, parent (fix^1) `fe6308b281ded7377c927b78fb0390d5816ba492` +- advisory title: Missing permission check in Jenkins CloudBees CD Plugin allows scheduling builds + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-electricflow-plugin-b319df3a71ebd890` | `src/main/java/org/jenkinsci/plugins/electricflow/rest/ElectricFlowEFRunAPIAction.java::doBuild` (71-189) | java | HTTP POST to the ElectricFlowEFRunAPIAction endpoint (getUrlName() URL_NAME) invoking doBuild(StaplerRequest, StaplerResponse); attacker-controlled JSON body read via req.getReader() supplies flowRunt | 0.9 | + +## jenkinsci/git-plugin + +- advisory: GHSA-449w-c77c-vmf6 (access_control, CWE-306), origin `?`, ecosystem ?, licence ? +- fix `b46165c74a0bf15e08763de2e506005624d5d238`, parent (fix^1) `18577d14afa2d1fbf970c44f60fce426d083073b` +- advisory title: Lack of authentication mechanism in Jenkins Git Plugin webhook + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-git-plugin-751c41fb6795520f` | `src/main/java/hudson/plugins/git/GitStatus.java::doNotifyCommit` (115-177) | java | /git/notifyCommit webhook endpoint handled by GitStatus.doNotifyCommit(HttpServletRequest, url, branches, sha1) | 0.95 | + +## jenkinsci/global-build-stats-plugin + +- advisory: GHSA-gm8g-fh49-qq6v (access_control, CWE-284), origin `?`, ecosystem ?, licence ? +- fix `32aeb0493c4ff5423448576f477ac612f7a25138`, parent (fix^1) `6478447abafa3d984bdfb4f73a358b68a97bdcf3` +- advisory title: Jenkins global-build-stats Plugin missing permission check can result in graph IDs being enumerated + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-global-build-stats-plugin-b2560994597ff44f` | `src/main/java/hudson/plugins/global_build_stats/GlobalBuildStatsPlugin.java::doPython` (130-136) | java | GlobalBuildStatsApi.doPython (and doJson/doXml) REST API endpoint via Stapler, source: buildStatConfigId request parameter | 0.9 | +| `jenkinsci-global-build-stats-plugin-ee8d1b0fdf63b4ee` | `src/main/java/hudson/plugins/global_build_stats/GlobalBuildStatsPlugin.java::doJson` (123-129) | java | GlobalBuildStatsApi.doJson (REST API endpoint /api/json via getApi()), source: buildStatConfigId request parameter | 0.85 | + +## jenkinsci/groovy-plugin + +- advisory: GHSA-xfwj-2f34-32f5 (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `212e048a319ae32dad4cfec5e73a885a9f4781f0`, parent (fix^1) `da0739d3507c5973d506d18efbda33ad5e37893b` +- advisory title: Jenkins Groovy Plugin sandbox bypass vulnerability + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-groovy-plugin-74141466f39e1a12` | `src/main/java/hudson/plugins/groovy/StringScriptSource.java::doCheckScript` (65-77) | java | Jenkins HTTP endpoint invoking DescriptorImpl.doCheckScript with @QueryParameter String command (Groovy command script source descriptor) | 0.85 | + +## jenkinsci/hashicorp-vault-plugin + +- advisory: GHSA-vpf7-q2rx-26mh (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `3b38d767aba8bd98d6f4fb53c1f1678d95b5e752`, parent (fix^1) `db858fd6bf48b0784598b8f1b12d006c8d6dec98` +- advisory title: Jenkins HashiCorp Vault Plugin does not perform permission checks in several HTTP endpoints that perform Vault connection tests + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-hashicorp-vault-plugin-4b8dac7099e598b2` | `src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultUsernamePasswordCredentialImpl.java::doTestConnection` (81-105) | java | Jenkins Stapler HTTP endpoint DescriptorImpl.doTestConnection (Vault Username-Password Credential descriptor), invoked via form validation request with attacker-controlled query parameters path, usern | 0.9 | +| `jenkinsci-hashicorp-vault-plugin-69b136827df9a5c0` | `src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultSSHUserPrivateKeyImpl.java::doTestConnection` (115-147) | java | Jenkins Stapler HTTP endpoint doTestConnection on VaultSSHUserPrivateKeyImpl.DescriptorImpl (e.g. /descriptorByName/.../testConnection), with attacker-controlled query parameters path, usernameKey, pr | 0.9 | +| `jenkinsci-hashicorp-vault-plugin-7782cfb6ae3f0339` | `src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultStringCredentialImpl.java::doTestConnection` (59-75) | java | Jenkins Stapler HTTP endpoint doTestConnection on VaultStringCredentialImpl.DescriptorImpl, invoked via the credential configuration form with attacker-controlled query parameters path, vaultKey, pref | 0.85 | +| `jenkinsci-hashicorp-vault-plugin-9f7965aeec3cc869` | `src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultCertificateCredentialsImpl.java::doTestConnection` (139-162) | java | Jenkins Stapler HTTP endpoint DescriptorImpl.doTestConnection (e.g. /descriptorByName/.../testConnection) with @QueryParameter path/keyStoreKey/passwordKey/prefixPath/namespace/engineVersion | 0.85 | +| `jenkinsci-hashicorp-vault-plugin-c76a541ee22b2ef9` | `src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultFileCredentialImpl.java::doTestConnection` (91-120) | java | Jenkins Stapler HTTP endpoint doTestConnection on VaultFileCredentialImpl.DescriptorImpl (e.g. /descriptorByName/com.datapipe.jenkins.vault.credentials.common.VaultFileCredentialImpl/testConnection), | 0.85 | +| `jenkinsci-hashicorp-vault-plugin-e7d568b004427b1d` | `src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultGCRLoginImpl.java::doTestConnection` (60-78) | java | Jenkins Stapler HTTP endpoint DescriptorImpl.doTestConnection (e.g. /descriptorByName/.../testConnection) with @QueryParameter path/prefixPath/namespace/engineVersion | 0.85 | + +## jenkinsci/jiratestresultreporter-plugin + +- advisory: GHSA-gc7m-x2cj-3775 (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `0cc6208295b5cb683528e8bf04d139f0bee8eb53`, parent (fix^1) `81792855394237a2f78b06f509985a894ac5c008` +- advisory title: Missing permission check in Jenkins JiraTestResultReporter Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-jiratestresultreporter-plugin-28213733c6b799eb` | `src/main/java/org/jenkinsci/plugins/JiraTestResultReporter/JiraTestDataPublisher.java::doValidateGlobal` (511-544) | java | Jenkins Stapler HTTP endpoint doValidateGlobal on JiraTestDataPublisher (global.jelly 'Validate Settings' button), parameters jiraUrl/username/password | 0.9 | + +## jenkinsci/jx-resources-plugin + +- advisory: GHSA-xqqr-mq8x-22qx (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `f0d9fb76230b65e851095da936a439d953c5f64d`, parent (fix^1) `520f0a91dd01f404d29cee07433635e43c474294` +- advisory title: Jenkins JX Resources Plugin missing permission check + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-jx-resources-plugin-e1eb49dbe32bfc7a` | `src/main/java/org/jenkinsci/plugins/jx/resources/GlobalPluginConfiguration.java::doValidateClient` (129-141) | java | Jenkins form validation endpoint doValidateClient (GlobalPluginConfiguration), invoked via Jenkins form validation HTTP request with attacker-controlled 'server' and 'namespace' query parameters | 0.85 | + +## jenkinsci/mabl-integration-plugin + +- advisory: GHSA-m9jj-p947-m8xv (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `4e21f498b0704d62f5a6114fcd8c274a5f440b18`, parent (fix^1) `61281f28815b3e05ca3d156f5b080fdde34ba1df` +- advisory title: Jenkins mabl Plugin missing permission check + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-mabl-integration-plugin-010c7741299085f7` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::doFillApplicationIdItems` (361-382) | java | Jenkins Stapler HTTP endpoint doFillApplicationIdItems (e.g. /job//descriptorByName/com.mabl.integration.jenkins.MablStepBuilder/fillApplicationIdItems) with attacker-controlled query parameters | 0.85 | +| `jenkinsci-mabl-integration-plugin-33601449707f721c` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::doFillRestApiKeyIdItems` (328-342) | java | Jenkins Stapler HTTP endpoint doFillRestApiKeyIdItems (e.g. /job//descriptorByName/com.mabl.integration.jenkins.MablStepBuilder/fillRestApiKeyIdItems) invoked with attacker-controlled restApiKey | 0.85 | +| `jenkinsci-mabl-integration-plugin-5f366608a3d422b4` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::getApplicationIdItems` (384-407) | java | doFillApplicationIdItems HTTP endpoint (Jenkins Stapler @QueryParameter restApiKeyId, disableSslVerification, apiBaseUrl, appBaseUrl) reachable by users with Overall/Read permission | 0.85 | +| `jenkinsci-mabl-integration-plugin-60b82fbf81b044f5` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::doCheckRestApiKeyIds` (344-359) | java | Jenkins Stapler HTTP endpoint doCheckRestApiKeyIds (and doFillApplicationIdItems) on MablStepBuilder, invoked via the mabl build step configuration form; attacker-controlled source is the @QueryParame | 0.85 | +| `jenkinsci-mabl-integration-plugin-8cc76fc9d5aa0984` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::doFillEnvironmentIdItems` (409-426) | java | Jenkins Stapler HTTP endpoint doFillEnvironmentIdItems (MablStepBuilder), reachable via GET/POST to the descriptor fill URL with attacker-controlled query parameters restApiKeyId, disableSslVerificati | 0.85 | +| `jenkinsci-mabl-integration-plugin-b2206be4bf8e37fb` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::doValidateForm` (316-326) | java | MablStepDescriptor.doValidateForm HTTP endpoint (Stapler @QueryParameter restApiKeyId/environmentId/applicationId/disableSslVerification/apiBaseUrl/appBaseUrl) | 0.85 | +| `jenkinsci-mabl-integration-plugin-c9df9fe333e3ed08` | `src/main/java/com/mabl/integration/jenkins/MablStepBuilder.java::getEnvironmentIdItems` (428-466) | java | doFillEnvironmentIdItems (Jenkins Stapler HTTP endpoint, @QueryParameter restApiKeyId/apiBaseUrl/appBaseUrl/disableSslVerification) | 0.85 | + +## jenkinsci/nomad-plugin + +- advisory: GHSA-p278-2qh9-6mwj (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `93ea215a649575e4063e1dfe8361b684c29a91e3`, parent (fix^1) `fe2cc9498561b357c7b1a17fc3b76a492abff755` +- advisory title: Jenkins Nomad Plugin missing permission check + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-nomad-plugin-81a6fad8feb01b11` | `src/main/java/org/jenkinsci/plugins/nomad/NomadCloud.java::doCheckName` (224-233) | java | NomadCloud.DescriptorImpl#doCheckName form validation endpoint (Jenkins Stapler HTTP route /descriptorByName/org.jenkinsci.plugins.nomad.NomadCloud/checkName), source: @QueryParameter String name | 0.75 | + +## jenkinsci/opentelemetry-plugin + +- advisory: GHSA-f696-867g-2759 (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `f5a4ec123769096ad9a4930ede56588b0fee40f3`, parent (fix^1) `26675a20647122918cb1cf154470e7e71ff1882f` +- advisory title: Jenkins OpenTelemetry Plugin missing permission check allows capturing credentials + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-opentelemetry-plugin-62ce6dc3488e0d80` | `src/main/java/io/jenkins/plugins/opentelemetry/backend/elastic/ElasticLogsBackendWithJenkinsVisualization.java::doCheckElasticsearchCredentialsId` (157-173) | java | Jenkins Stapler HTTP endpoint doCheckElasticsearchCredentialsId (form validation for ElasticLogsBackendWithJenkinsVisualization), invoked via POST with elasticsearchCredentialsId query parameter by a | 0.85 | +| `jenkinsci-opentelemetry-plugin-c258c6ed37f2c061` | `src/main/java/io/jenkins/plugins/opentelemetry/backend/elastic/ElasticLogsBackendWithJenkinsVisualization.java::doFillElasticsearchCredentialsIdItems` (144-154) | java | Jenkins Stapler HTTP endpoint doFillElasticsearchCredentialsIdItems on the ElasticLogsBackendWithJenkinsVisualization.DescriptorImpl (invoked via the plugin configuration form, e.g. /descriptorByName/ | 0.75 | +| `jenkinsci-opentelemetry-plugin-e7dc96d707803ae7` | `src/main/java/io/jenkins/plugins/opentelemetry/backend/elastic/ElasticLogsBackendWithJenkinsVisualization.java::doCheckElasticsearchUrl` (131-197) | java | Jenkins Stapler HTTP endpoint DescriptorImpl.doValidate (and doCheckElasticsearchUrl/doCheckElasticsearchCredentialsId) invoked via form validation request with attacker-controlled elasticsearchUrl an | 0.85 | +| `jenkinsci-opentelemetry-plugin-f0ff00bf7375eb29` | `src/main/java/io/jenkins/plugins/opentelemetry/backend/elastic/ElasticLogsBackendWithJenkinsVisualization.java::doValidate` (176-195) | java | Jenkins Stapler HTTP endpoint doValidate on ElasticLogsBackendWithJenkinsVisualization (POST form validation), attacker-controlled elasticsearchUrl and elasticsearchCredentialsId query parameters | 0.85 | + +## jenkinsci/rocketchatnotifier-plugin + +- advisory: GHSA-4p8f-2fwv-6xcw (access_control, CWE-862), origin `?`, ecosystem ?, licence ? +- fix `1a0023be9f2e143434d028d5292ef9dc3195d051`, parent (fix^1) `14cdaa96d98d6d65fbefde1103a04bc478edf415` +- advisory title: Missing permission check in Jenkins RocketChat Notifier Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-rocketchatnotifier-plugin-16d28ce862d5a528` | `src/main/java/jenkins/plugins/rocketchatnotifier/RocketChatNotifier.java::doTestConnection` (581-647) | java | Jenkins Stapler form validation endpoint doTestConnection (e.g. /descriptorByName/jenkins.plugins.rocketchatnotifier.RocketChatNotifier/doTestConnection) with attacker-controlled query parameters rock | 0.9 | + +## jenkinsci/support-core-plugin + +- advisory: GHSA-w2j3-pq63-339w (access_control, CWE-863), origin `?`, ecosystem ?, licence ? +- fix `9b7a1d48db0fdfb840ca3393e9462e687e69385b`, parent (fix^1) `abaff0102139d9ec56ce3905f2ffef27649c88a4` +- advisory title: Incorrect permission checks in Jenkins Support Core Plugin + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `jenkinsci-support-core-plugin-3de9ccb2591c7490` | `src/main/java/com/cloudbees/jenkins/support/SupportCommand.java::run` (77-122) | java | Jenkins CLI command 'support' (SupportCommand.run) invoked via CLI channel; attacker-controlled source is the CLI invocation by a user holding Support/DownloadBundle permission | 0.85 | +| `jenkinsci-support-core-plugin-934a17bf668da541` | `src/main/java/com/cloudbees/jenkins/support/SupportAction.java::Restricted` (89-93) | java | SupportAction (RootAction, urlName "support") via StaplerProxy getTarget(); HTTP request to /support/... reaches getTarget() which checks CREATE_BUNDLE (Support/DownloadBundle) instead of Jenkins.ADMI | 0.85 | + +## kimai/kimai + +- advisory: GHSA-9w8f-7wgr-2h7g (access_control, CWE-284), origin `?`, ecosystem ?, licence ? +- fix `ff9acab0fc81f0e9490462739ef15fe4ab028ea5`, parent (fix^1) `76e09447c85e762882126b49626a4fe4d93fe8b5` +- advisory title: kimai2 is vulnerable to Improper Access Control + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `kimai-kimai-166480170479d403` | `src/Controller/InvoiceController.php::createInvoiceAction` (166-185) | php | GET /save-invoice/{customer}/{template} (route name invoice_create) in InvoiceController::createInvoiceAction | 0.75 | +| `kimai-kimai-5e04ee92bdb735ea` | `src/Controller/InvoiceController.php::previewAction` (136-165) | php | GET /preview/{customer}/{template} route (invoice_preview) in InvoiceController::previewAction; attacker-controlled source is the {customer} route parameter (Customer entity) and {template} parameter, | 0.85 | + +## mage-ai/mage-ai + +- advisory: GHSA-c6mm-2g84-v4m7 (access_control, CWE-306), origin `?`, ecosystem ?, licence ? +- fix `f63cd00f6a3be372397d37a4c9a49bfaf50d7650`, parent (fix^1) `e16a64962d540046b1210b5b749897cf600f0ed3` +- advisory title: Mage-ai missing user authentication + +| id | path::function (pre-fix lines) | language | entry point (verifier) | confidence | +|---|---|---|---|---| +| `mage-ai-mage-ai-c9810ee637c308c0` | `mage_ai/server/terminal_server.py::open` (54-93) | python | WebSocket TerminalWebsocketServer.open (terminal_server.py) via /terminals/websocket route; attacker-controlled source: websocket query arguments api_key, token, cwd, term_name | 0.85 | +| `mage-ai-mage-ai-d1ee6d54adc38f57` | `mage_ai/frontend/components/Terminal/index.tsx::Terminal` (43-407) | typescript | Terminal component (mage_ai/frontend/components/Terminal/index.tsx) rendered in the Mage web UI; keyboard input via registerOnKeyDown and sendMessage WebSocket channel | 0.6 | + diff --git a/benchmarks/valid/train/catalog_access_control.toml b/benchmarks/valid/train/catalog_access_control.toml new file mode 100644 index 0000000..0f1f198 --- /dev/null +++ b/benchmarks/valid/train/catalog_access_control.toml @@ -0,0 +1,2663 @@ +[[case]] +advisory = "GHSA-79vv-vp32-gpp7" +advisory_text = "Apache Kafka: Potential incorrect access control during migration from ZK mode to KRaft mode\n\nWhile an Apache Kafka cluster is being migrated from ZooKeeper mode to KRaft mode, in some cases ACLs will not be correctly enforced.\n\nTwo preconditions are needed to trigger the bug:\n1. The administrator decides to remove an ACL\n2. The resource associated with the removed ACL continues to have two or more other ACLs associated with it after the removal.\n\nWhen those two preconditions are met, Kafka will treat the resource as if it had only one ACL associated with it after the removal, rather than the two or more that would be correct.\n\nThe incorrect condition is cleared by removing all brokers in ZK mode, or by adding a new ACL to the affected resource. Once the migration is completed, there is no metadata loss (the ACLs all remain).\n\nThe full impact depends on the ACLs in use. If only ALLOW ACLs were configured during the migration, the impact would be limited to availability impact. if DENY ACLs were configured, the impact could include confidentiality and integrity impact depending on the ACLs configured, as the DENY ACLs might be ignored due to this vulnerability during the migration period." +commit = "c000b1fae2bd7d4b76713a53508f128a13431ab6" +cwe = "CWE-863" +family = "access_control" +function = "KRaftMigrationDriver" +function_lines = [[117, 150]] +id = "apache-kafka-46a9a98dac1bc81e" +language = "java" +method = "fix_site" +parent = "08b68583fa1042c9b9473e4dc9352a3b45c772fb" +path = "metadata/src/main/java/org/apache/kafka/metadata/migration/KRaftMigrationDriver.java" +post_fix = " KRaftMigrationDriver(\n int nodeId,\n ZkRecordConsumer zkRecordConsumer,\n MigrationClient zkMigrationClient,\n LegacyPropagator propagator,\n Consumer initialZkLoadHandler,\n FaultHandler faultHandler,\n QuorumFeatures quorumFeatures,\n KafkaConfigSchema configSchema,\n QuorumControllerMetrics controllerMetrics,\n int minBatchSize,\n Time time\n ) {\n this.nodeId = nodeId;\n this.zkRecordConsumer = zkRecordConsumer;\n this.zkMigrationClient = zkMigrationClient;\n this.propagator = propagator;\n this.time = time;\n LogContext logContext = new LogContext(\"[KRaftMigrationDriver id=\" + nodeId + \"] \");\n this.controllerMetrics = controllerMetrics;\n Logger log = logContext.logger(KRaftMigrationDriver.class);\n this.log = log;\n this.migrationState = MigrationDriverState.UNINITIALIZED;\n this.migrationLeadershipState = ZkMigrationLeadershipState.EMPTY;\n this.eventQueue = new KafkaEventQueue(Time.SYSTEM, logContext, \"controller-\" + nodeId + \"-migration-driver-\");\n this.pollTimeSupplier = new PollTimeSupplier();\n this.image = MetadataImage.EMPTY;\n this.firstPublish = false;\n this.initialZkLoadHandler = initialZkLoadHandler;\n this.faultHandler = faultHandler;\n this.quorumFeatures = quorumFeatures;\n this.zkMetadataWriter = new KRaftMigrationZkWriter(zkMigrationClient, log::error);\n this.recordRedactor = new RecordRedactor(configSchema);\n this.minBatchSize = minBatchSize;\n }" +pre_fix = " KRaftMigrationDriver(\n int nodeId,\n ZkRecordConsumer zkRecordConsumer,\n MigrationClient zkMigrationClient,\n LegacyPropagator propagator,\n Consumer initialZkLoadHandler,\n FaultHandler faultHandler,\n QuorumFeatures quorumFeatures,\n KafkaConfigSchema configSchema,\n QuorumControllerMetrics controllerMetrics,\n int minBatchSize,\n Time time\n ) {\n this.nodeId = nodeId;\n this.zkRecordConsumer = zkRecordConsumer;\n this.zkMigrationClient = zkMigrationClient;\n this.propagator = propagator;\n this.time = time;\n LogContext logContext = new LogContext(\"[KRaftMigrationDriver id=\" + nodeId + \"] \");\n this.controllerMetrics = controllerMetrics;\n this.log = logContext.logger(KRaftMigrationDriver.class);\n this.migrationState = MigrationDriverState.UNINITIALIZED;\n this.migrationLeadershipState = ZkMigrationLeadershipState.EMPTY;\n this.eventQueue = new KafkaEventQueue(Time.SYSTEM, logContext, \"controller-\" + nodeId + \"-migration-driver-\");\n this.pollTimeSupplier = new PollTimeSupplier();\n this.image = MetadataImage.EMPTY;\n this.firstPublish = false;\n this.initialZkLoadHandler = initialZkLoadHandler;\n this.faultHandler = faultHandler;\n this.quorumFeatures = quorumFeatures;\n this.zkMetadataWriter = new KRaftMigrationZkWriter(zkMigrationClient);\n this.recordRedactor = new RecordRedactor(configSchema);\n this.minBatchSize = minBatchSize;\n }" +repo = "apache/kafka" +url = "https://github.com/apache/kafka.git" + +[[case]] +advisory = "GHSA-79vv-vp32-gpp7" +advisory_text = "Apache Kafka: Potential incorrect access control during migration from ZK mode to KRaft mode\n\nWhile an Apache Kafka cluster is being migrated from ZooKeeper mode to KRaft mode, in some cases ACLs will not be correctly enforced.\n\nTwo preconditions are needed to trigger the bug:\n1. The administrator decides to remove an ACL\n2. The resource associated with the removed ACL continues to have two or more other ACLs associated with it after the removal.\n\nWhen those two preconditions are met, Kafka will treat the resource as if it had only one ACL associated with it after the removal, rather than the two or more that would be correct.\n\nThe incorrect condition is cleared by removing all brokers in ZK mode, or by adding a new ACL to the affected resource. Once the migration is completed, there is no metadata loss (the ACLs all remain).\n\nThe full impact depends on the ACLs in use. If only ALLOW ACLs were configured during the migration, the impact would be limited to availability impact. if DENY ACLs were configured, the impact could include confidentiality and integrity impact depending on the ACLs configured, as the DENY ACLs might be ignored due to this vulnerability during the migration period." +commit = "c000b1fae2bd7d4b76713a53508f128a13431ab6" +cwe = "CWE-863" +family = "access_control" +function = "KRaftMigrationZkWriter" +function_lines = [[86, 90]] +id = "apache-kafka-758e1fc455e8d3d4" +language = "java" +method = "fix_site" +parent = "08b68583fa1042c9b9473e4dc9352a3b45c772fb" +path = "metadata/src/main/java/org/apache/kafka/metadata/migration/KRaftMigrationZkWriter.java" +post_fix = " public KRaftMigrationZkWriter(\n MigrationClient migrationClient,\n Consumer errorLogger\n ) {\n this.migrationClient = migrationClient;\n this.errorLogger = errorLogger;\n }" +pre_fix = " public KRaftMigrationZkWriter(\n MigrationClient migrationClient\n ) {\n this.migrationClient = migrationClient;\n }" +repo = "apache/kafka" +url = "https://github.com/apache/kafka.git" + +[[case]] +advisory = "GHSA-79vv-vp32-gpp7" +advisory_text = "Apache Kafka: Potential incorrect access control during migration from ZK mode to KRaft mode\n\nWhile an Apache Kafka cluster is being migrated from ZooKeeper mode to KRaft mode, in some cases ACLs will not be correctly enforced.\n\nTwo preconditions are needed to trigger the bug:\n1. The administrator decides to remove an ACL\n2. The resource associated with the removed ACL continues to have two or more other ACLs associated with it after the removal.\n\nWhen those two preconditions are met, Kafka will treat the resource as if it had only one ACL associated with it after the removal, rather than the two or more that would be correct.\n\nThe incorrect condition is cleared by removing all brokers in ZK mode, or by adding a new ACL to the affected resource. Once the migration is completed, there is no metadata loss (the ACLs all remain).\n\nThe full impact depends on the ACLs in use. If only ALLOW ACLs were configured during the migration, the impact would be limited to availability impact. if DENY ACLs were configured, the impact could include confidentiality and integrity impact depending on the ACLs configured, as the DENY ACLs might be ignored due to this vulnerability during the migration period." +commit = "c000b1fae2bd7d4b76713a53508f128a13431ab6" +cwe = "CWE-863" +family = "access_control" +function = "handleAclsSnapshot" +function_lines = [[569, 614]] +id = "apache-kafka-80ecbb6e2b4c894e" +language = "java" +method = "fix_site" +parent = "08b68583fa1042c9b9473e4dc9352a3b45c772fb" +path = "metadata/src/main/java/org/apache/kafka/metadata/migration/KRaftMigrationZkWriter.java" +post_fix = " void handleAclsSnapshot(AclsImage image, KRaftMigrationOperationConsumer operationConsumer) {\n // Need to compare contents of image with all ACLs in ZK and issue updates\n Map> allAclsInSnapshot = new HashMap<>();\n\n image.acls().values().forEach(standardAcl -> {\n ResourcePattern resourcePattern = resourcePatternFromAcl(standardAcl);\n allAclsInSnapshot.computeIfAbsent(resourcePattern, __ -> new HashSet<>()).add(\n new AccessControlEntry(standardAcl.principal(), standardAcl.host(), standardAcl.operation(), standardAcl.permissionType())\n );\n });\n\n Set newResources = new HashSet<>(allAclsInSnapshot.keySet());\n Set resourcesToDelete = new HashSet<>();\n Map> changedResources = new HashMap<>();\n migrationClient.aclClient().iterateAcls((resourcePattern, accessControlEntries) -> {\n newResources.remove(resourcePattern);\n if (!allAclsInSnapshot.containsKey(resourcePattern)) {\n resourcesToDelete.add(resourcePattern);\n } else {\n Set snapshotEntries = allAclsInSnapshot.get(resourcePattern);\n if (!snapshotEntries.equals(accessControlEntries)) {\n changedResources.put(resourcePattern, snapshotEntries);\n }\n }\n });\n\n newResources.forEach(resourcePattern -> {\n // newResources is generated from allAclsInSnapshot, and we don't remove from that map, so this unguarded .get() is safe\n Set accessControlEntries = allAclsInSnapshot.get(resourcePattern);\n String name = \"Writing \" + accessControlEntries.size() + \" for resource \" + resourcePattern;\n operationConsumer.accept(UPDATE_ACL, name, migrationState ->\n migrationClient.aclClient().writeResourceAcls(resourcePattern, accessControlEntries, migrationState));\n });\n\n resourcesToDelete.forEach(deletedResource -> {\n String name = \"Deleting resource \" + deletedResource + \" which has no ACLs in snapshot\";\n operationConsumer.accept(DELETE_ACL, name, migrationState ->\n migrationClient.aclClient().deleteResource(deletedResource, migrationState));\n });\n\n changedResources.forEach((resourcePattern, accessControlEntries) -> {\n String name = \"Writing \" + accessControlEntries.size() + \" for resource \" + resourcePattern;\n operationConsumer.accept(UPDATE_ACL, name, migrationState ->\n migrationClient.aclClient().writeResourceAcls(resourcePattern, accessControlEntries, migrationState));\n });\n }\n" +pre_fix = " void handleAclsSnapshot(AclsImage image, KRaftMigrationOperationConsumer operationConsumer) {\n // Need to compare contents of image with all ACLs in ZK and issue updates\n Map> allAclsInSnapshot = new HashMap<>();\n\n image.acls().values().forEach(standardAcl -> {\n ResourcePattern resourcePattern = resourcePatternFromAcl(standardAcl);\n allAclsInSnapshot.computeIfAbsent(resourcePattern, __ -> new HashSet<>()).add(\n new AccessControlEntry(standardAcl.principal(), standardAcl.host(), standardAcl.operation(), standardAcl.permissionType())\n );\n });\n\n Set newResources = new HashSet<>(allAclsInSnapshot.keySet());\n Set resourcesToDelete = new HashSet<>();\n Map> changedResources = new HashMap<>();\n migrationClient.aclClient().iterateAcls((resourcePattern, accessControlEntries) -> {\n newResources.remove(resourcePattern);\n if (!allAclsInSnapshot.containsKey(resourcePattern)) {\n resourcesToDelete.add(resourcePattern);\n } else {\n Set snapshotEntries = allAclsInSnapshot.get(resourcePattern);\n if (!snapshotEntries.equals(accessControlEntries)) {\n changedResources.put(resourcePattern, snapshotEntries);\n }\n }\n });\n\n newResources.forEach(resourcePattern -> {\n Set accessControlEntries = allAclsInSnapshot.get(resourcePattern);\n String name = \"Writing \" + accessControlEntries.size() + \" for resource \" + resourcePattern;\n operationConsumer.accept(UPDATE_ACL, name, migrationState ->\n migrationClient.aclClient().writeResourceAcls(resourcePattern, accessControlEntries, migrationState));\n });\n\n resourcesToDelete.forEach(deletedResource -> {\n String name = \"Deleting resource \" + deletedResource + \" which has no ACLs in snapshot\";\n operationConsumer.accept(DELETE_ACL, name, migrationState ->\n migrationClient.aclClient().deleteResource(deletedResource, migrationState));\n });\n\n changedResources.forEach((resourcePattern, accessControlEntries) -> {\n String name = \"Writing \" + accessControlEntries.size() + \" for resource \" + resourcePattern;\n operationConsumer.accept(UPDATE_ACL, name, migrationState ->\n migrationClient.aclClient().writeResourceAcls(resourcePattern, accessControlEntries, migrationState));\n });\n }\n" +repo = "apache/kafka" +url = "https://github.com/apache/kafka.git" + +[[case]] +advisory = "GHSA-79vv-vp32-gpp7" +advisory_text = "Apache Kafka: Potential incorrect access control during migration from ZK mode to KRaft mode\n\nWhile an Apache Kafka cluster is being migrated from ZooKeeper mode to KRaft mode, in some cases ACLs will not be correctly enforced.\n\nTwo preconditions are needed to trigger the bug:\n1. The administrator decides to remove an ACL\n2. The resource associated with the removed ACL continues to have two or more other ACLs associated with it after the removal.\n\nWhen those two preconditions are met, Kafka will treat the resource as if it had only one ACL associated with it after the removal, rather than the two or more that would be correct.\n\nThe incorrect condition is cleared by removing all brokers in ZK mode, or by adding a new ACL to the affected resource. Once the migration is completed, there is no metadata loss (the ACLs all remain).\n\nThe full impact depends on the ACLs in use. If only ALLOW ACLs were configured during the migration, the impact would be limited to availability impact. if DENY ACLs were configured, the impact could include confidentiality and integrity impact depending on the ACLs configured, as the DENY ACLs might be ignored due to this vulnerability during the migration period." +commit = "c000b1fae2bd7d4b76713a53508f128a13431ab6" +cwe = "CWE-863" +family = "access_control" +function = "handleAclsDelta" +function_lines = [[615, 654]] +id = "apache-kafka-86d9d7a9718034e3" +language = "java" +method = "fix_site" +parent = "08b68583fa1042c9b9473e4dc9352a3b45c772fb" +path = "metadata/src/main/java/org/apache/kafka/metadata/migration/KRaftMigrationZkWriter.java" +post_fix = " void handleAclsDelta(AclsImage prevImage, AclsImage image, AclsDelta delta, KRaftMigrationOperationConsumer operationConsumer) {\n // Need to collect all ACLs for any changed resource pattern\n Map> aclsToWrite = new HashMap<>();\n delta.changes().forEach((aclId, aclChange) -> {\n if (aclChange.isPresent()) {\n ResourcePattern resourcePattern = resourcePatternFromAcl(aclChange.get());\n aclsToWrite.put(resourcePattern, new ArrayList<>());\n } else {\n // We need to look in the previous image to get deleted ACLs resource pattern\n StandardAcl deletedAcl = prevImage.acls().get(aclId);\n if (deletedAcl == null) {\n errorLogger.accept(\"Cannot delete ACL \" + aclId + \" from ZK since it is missing from previous AclImage\");\n } else {\n ResourcePattern resourcePattern = resourcePatternFromAcl(deletedAcl);\n aclsToWrite.put(resourcePattern, new ArrayList<>());\n }\n }\n });\n\n // Iterate through the new image to collect any ACLs for these changed resources\n image.acls().forEach((uuid, standardAcl) -> {\n ResourcePattern resourcePattern = resourcePatternFromAcl(standardAcl);\n List entries = aclsToWrite.get(resourcePattern);\n if (entries != null) {\n entries.add(new AccessControlEntry(standardAcl.principal(), standardAcl.host(), standardAcl.operation(), standardAcl.permissionType()));\n }\n });\n\n // If there are no more ACLs for a resource, delete it. Otherwise, update it with the new set of ACLs\n aclsToWrite.forEach((resourcePattern, accessControlEntries) -> {\n if (accessControlEntries.isEmpty()) {\n String name = \"Deleting resource \" + resourcePattern + \" which has no more ACLs\";\n operationConsumer.accept(DELETE_ACL, name, migrationState ->\n migrationClient.aclClient().deleteResource(resourcePattern, migrationState));\n } else {\n String name = \"Writing \" + accessControlEntries.size() + \" for resource \" + resourcePattern;\n operationConsumer.accept(UPDATE_ACL, name, migrationState ->\n migrationClient.aclClient().writeResourceAcls(resourcePattern, accessControlEntries, migrationState));\n }\n });\n }\n" +pre_fix = " void handleAclsDelta(AclsImage image, AclsDelta delta, KRaftMigrationOperationConsumer operationConsumer) {\n // Compute the resource patterns that were changed\n Set resourcesWithChangedAcls = delta.changes().values()\n .stream()\n .filter(Optional::isPresent)\n .map(Optional::get)\n .map(this::resourcePatternFromAcl)\n .collect(Collectors.toSet());\n\n Set resourcesWithDeletedAcls = delta.deleted()\n .stream()\n .map(this::resourcePatternFromAcl)\n .collect(Collectors.toSet());\n\n // Need to collect all ACLs for any changed resource pattern\n Map> aclsToWrite = new HashMap<>();\n image.acls().forEach((uuid, standardAcl) -> {\n ResourcePattern resourcePattern = resourcePatternFromAcl(standardAcl);\n boolean removed = resourcesWithDeletedAcls.remove(resourcePattern);\n // If a resource pattern is present in the delta as a changed or deleted acl, need to include it\n if (resourcesWithChangedAcls.contains(resourcePattern) || removed) {\n aclsToWrite.computeIfAbsent(resourcePattern, __ -> new ArrayList<>()).add(\n new AccessControlEntry(standardAcl.principal(), standardAcl.host(), standardAcl.operation(), standardAcl.permissionType())\n );\n }\n });\n\n resourcesWithDeletedAcls.forEach(deletedResource -> {\n String name = \"Deleting resource \" + deletedResource + \" which has no more ACLs\";\n operationConsumer.accept(DELETE_ACL, name, migrationState ->\n migrationClient.aclClient().deleteResource(deletedResource, migrationState));\n });\n\n aclsToWrite.forEach((resourcePattern, accessControlEntries) -> {\n String name = \"Writing \" + accessControlEntries.size() + \" for resource \" + resourcePattern;\n operationConsumer.accept(UPDATE_ACL, name, migrationState ->\n migrationClient.aclClient().writeResourceAcls(resourcePattern, accessControlEntries, migrationState));\n });\n }\n" +repo = "apache/kafka" +url = "https://github.com/apache/kafka.git" + +[[case]] +advisory = "GHSA-79vv-vp32-gpp7" +advisory_text = "Apache Kafka: Potential incorrect access control during migration from ZK mode to KRaft mode\n\nWhile an Apache Kafka cluster is being migrated from ZooKeeper mode to KRaft mode, in some cases ACLs will not be correctly enforced.\n\nTwo preconditions are needed to trigger the bug:\n1. The administrator decides to remove an ACL\n2. The resource associated with the removed ACL continues to have two or more other ACLs associated with it after the removal.\n\nWhen those two preconditions are met, Kafka will treat the resource as if it had only one ACL associated with it after the removal, rather than the two or more that would be correct.\n\nThe incorrect condition is cleared by removing all brokers in ZK mode, or by adding a new ACL to the affected resource. Once the migration is completed, there is no metadata loss (the ACLs all remain).\n\nThe full impact depends on the ACLs in use. If only ALLOW ACLs were configured during the migration, the impact would be limited to availability impact. if DENY ACLs were configured, the impact could include confidentiality and integrity impact depending on the ACLs configured, as the DENY ACLs might be ignored due to this vulnerability during the migration period." +commit = "c000b1fae2bd7d4b76713a53508f128a13431ab6" +cwe = "CWE-863" +family = "access_control" +function = "handleDelta" +function_lines = [[101, 133]] +id = "apache-kafka-a24b53ecb07d6b36" +language = "java" +method = "fix_site" +parent = "08b68583fa1042c9b9473e4dc9352a3b45c772fb" +path = "metadata/src/main/java/org/apache/kafka/metadata/migration/KRaftMigrationZkWriter.java" +post_fix = " public boolean handleDelta(\n MetadataImage previousImage,\n MetadataImage image,\n MetadataDelta delta,\n KRaftMigrationOperationConsumer operationConsumer\n ) {\n boolean updated = false;\n if (delta.topicsDelta() != null) {\n handleTopicsDelta(previousImage.topics().topicIdToNameView()::get, image.topics(), delta.topicsDelta(), operationConsumer);\n updated = true;\n }\n if (delta.configsDelta() != null) {\n handleConfigsDelta(image.configs(), delta.configsDelta(), operationConsumer);\n updated = true;\n }\n if ((delta.clientQuotasDelta() != null) || (delta.scramDelta() != null)) {\n handleClientQuotasDelta(image, delta, operationConsumer);\n updated = true;\n }\n if (delta.producerIdsDelta() != null) {\n handleProducerIdDelta(delta.producerIdsDelta(), operationConsumer);\n updated = true;\n }\n if (delta.aclsDelta() != null) {\n handleAclsDelta(previousImage.acls(), image.acls(), delta.aclsDelta(), operationConsumer);\n updated = true;\n }\n if (delta.delegationTokenDelta() != null) {\n handleDelegationTokenDelta(image.delegationTokens(), delta.delegationTokenDelta(), operationConsumer);\n updated = true;\n }\n return updated;\n }" +pre_fix = " public boolean handleDelta(\n MetadataImage previousImage,\n MetadataImage image,\n MetadataDelta delta,\n KRaftMigrationOperationConsumer operationConsumer\n ) {\n boolean updated = false;\n if (delta.topicsDelta() != null) {\n handleTopicsDelta(previousImage.topics().topicIdToNameView()::get, image.topics(), delta.topicsDelta(), operationConsumer);\n updated = true;\n }\n if (delta.configsDelta() != null) {\n handleConfigsDelta(image.configs(), delta.configsDelta(), operationConsumer);\n updated = true;\n }\n if ((delta.clientQuotasDelta() != null) || (delta.scramDelta() != null)) {\n handleClientQuotasDelta(image, delta, operationConsumer);\n updated = true;\n }\n if (delta.producerIdsDelta() != null) {\n handleProducerIdDelta(delta.producerIdsDelta(), operationConsumer);\n updated = true;\n }\n if (delta.aclsDelta() != null) {\n handleAclsDelta(image.acls(), delta.aclsDelta(), operationConsumer);\n updated = true;\n }\n if (delta.delegationTokenDelta() != null) {\n handleDelegationTokenDelta(image.delegationTokens(), delta.delegationTokenDelta(), operationConsumer);\n updated = true;\n }\n return updated;\n }" +repo = "apache/kafka" +url = "https://github.com/apache/kafka.git" + +[[case]] +advisory = "GHSA-5993-wwpg-m92c" +advisory_text = "Apache Ozone user impersonation due to non-validation of Ozone S3 tokens\n\nIn Apache Ozone before 1.2.0, Authenticated users with valid Ozone S3 credentials can create specific OM requests, impersonating any other user." +commit = "60e078729e18ef1be276f35659957ac553d266f7" +cwe = "CWE-862" +family = "access_control" +function = "validateS3AuthInfo" +function_lines = [[472, 534]] +id = "apache-ozone-cdc7fa7f8ec13997" +language = "java" +method = "fix_site" +parent = "d054faa9b10f4c9ee323705d63abc1d28048da92" +path = "hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java" +post_fix = " private byte[] validateS3AuthInfo(OzoneTokenIdentifier identifier)\n throws InvalidToken {\n LOG.trace(\"Validating S3AuthInfo for identifier:{}\", identifier);\n if (identifier.getOwner() == null) {\n throw new InvalidToken(\n \"Owner is missing from the S3 auth token\");\n }\n if (!identifier.getOwner().toString().equals(identifier.getAwsAccessId())) {\n LOG.error(\n \"Owner and AWSAccessId is different in the S3 token. Possible \"\n + \" security attack: {}\",\n identifier);\n throw new InvalidToken(\n \"Invalid S3 identifier: owner=\" + identifier.getOwner()\n + \", awsAccessId=\" + identifier.getAwsAccessId());\n }\n String awsSecret;\n try {\n awsSecret = s3SecretManager.getS3UserSecretString(identifier\n .getAwsAccessId());\n } catch (IOException e) {\n LOG.error(\"Error while validating S3 identifier:{}\",\n identifier, e);\n throw new InvalidToken(\"No S3 secret found for S3 identifier:\"\n + identifier);\n }\n\n if (awsSecret == null) {\n throw new InvalidToken(\"No S3 secret found for S3 identifier:\"\n + identifier);\n }\n\n if (AWSV4AuthValidator.validateRequest(identifier.getStrToSign(),\n identifier.getSignature(), awsSecret)) {\n return identifier.getSignature().getBytes(UTF_8);\n }\n throw new InvalidToken(\"Invalid S3 identifier:\"\n + identifier);\n\n }\n\n private void loadTokenSecretState(\n OzoneManagerSecretState state) throws IOException {\n LOG.info(\"Loading token state into token manager.\");\n for (Map.Entry entry :\n state.getTokenState().entrySet()) {\n addPersistedDelegationToken(entry.getKey(), entry.getValue());\n }\n }\n\n private void addPersistedDelegationToken(OzoneTokenIdentifier identifier,\n long renewDate) throws IOException {\n if (isRunning()) {\n // a safety check\n throw new IOException(\n \"Can't add persisted delegation token to a running SecretManager.\");\n }\n\n byte[] password = createPassword(identifier.getBytes(),\n getCertClient().getPrivateKey());\n if (identifier.getSequenceNumber() > getDelegationTokenSeqNum()) {\n setDelegationTokenSeqNum(identifier.getSequenceNumber());\n }\n if (currentTokens.get(identifier) == null) {\n currentTokens.put(identifier, new TokenInfo(renewDate,\n password, identifier.getTrackingId()));\n } else {\n throw new IOException(\"Same delegation token being added twice: \"\n + formatTokenId(identifier));\n }\n }\n\n /**\n * Should be called before this object is used.\n */\n @Override" +pre_fix = " private byte[] validateS3AuthInfo(OzoneTokenIdentifier identifier)\n throws InvalidToken {\n LOG.trace(\"Validating S3AuthInfo for identifier:{}\", identifier);\n String awsSecret;\n try {\n awsSecret = s3SecretManager.getS3UserSecretString(identifier\n .getAwsAccessId());\n } catch (IOException e) {\n LOG.error(\"Error while validating S3 identifier:{}\",\n identifier, e);\n throw new InvalidToken(\"No S3 secret found for S3 identifier:\"\n + identifier);\n }\n\n if (awsSecret == null) {\n throw new InvalidToken(\"No S3 secret found for S3 identifier:\"\n + identifier);\n }\n\n if (AWSV4AuthValidator.validateRequest(identifier.getStrToSign(),\n identifier.getSignature(), awsSecret)) {\n return identifier.getSignature().getBytes(UTF_8);\n }\n throw new InvalidToken(\"Invalid S3 identifier:\"\n + identifier);\n\n }\n\n private void loadTokenSecretState(\n OzoneManagerSecretState state) throws IOException {\n LOG.info(\"Loading token state into token manager.\");\n for (Map.Entry entry :\n state.getTokenState().entrySet()) {\n addPersistedDelegationToken(entry.getKey(), entry.getValue());\n }\n }\n\n private void addPersistedDelegationToken(OzoneTokenIdentifier identifier,\n long renewDate) throws IOException {\n if (isRunning()) {\n // a safety check\n throw new IOException(\n \"Can't add persisted delegation token to a running SecretManager.\");\n }\n\n byte[] password = createPassword(identifier.getBytes(),\n getCertClient().getPrivateKey());\n if (identifier.getSequenceNumber() > getDelegationTokenSeqNum()) {\n setDelegationTokenSeqNum(identifier.getSequenceNumber());\n }\n if (currentTokens.get(identifier) == null) {\n currentTokens.put(identifier, new TokenInfo(renewDate,\n password, identifier.getTrackingId()));\n } else {\n throw new IOException(\"Same delegation token being added twice: \"\n + formatTokenId(identifier));\n }\n }\n\n /**\n * Should be called before this object is used.\n */\n @Override" +repo = "apache/ozone" +url = "https://github.com/apache/ozone.git" + +[[case]] +advisory = "GHSA-9x53-gr7p-4qf5" +advisory_text = "Apache SeaTunnel: Unauthenticated insecure access\n\n# Summary\n\nUnauthorized users can perform Arbitrary File Read and Deserialization\nattack by submit job using restful api-v1.\n\n# Details\nUnauthorized users can access `/hazelcast/rest/maps/submit-job` to submit\njob.\nAn attacker can set extra params in mysql url to perform Arbitrary File\nRead and Deserialization attack.\n\nThis issue affects Apache SeaTunnel: <=2.3.10\n\n# Fixed\n\nUsers are recommended to upgrade to version 2.3.11, and enable restful api-v2 & open https two-way authentication , which fixes the issue." +commit = "53325aa3e76e3939f41a4bf3eaaf3ee56f13f311" +cwe = "CWE-306" +family = "access_control" +function = "parseHttpConfig" +function_lines = [[493, 527]] +id = "apache-seatunnel-41f9a91b92ae6bec" +language = "java" +method = "fix_site" +parent = "8a9db476bdc37d5e4079491bdb7092b892a17a7b" +path = "seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/YamlSeaTunnelDomConfigProcessor.java" +post_fix = " private HttpConfig parseHttpConfig(Node httpNode) {\n HttpConfig httpConfig = new HttpConfig();\n for (Node node : childElements(httpNode)) {\n String name = cleanNodeName(node);\n if (ServerConfigOptions.MasterServerConfigOptions.PORT.key().equals(name)) {\n httpConfig.setPort(\n getIntegerValue(\n ServerConfigOptions.MasterServerConfigOptions.PORT.key(),\n getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.CONTEXT_PATH\n .key()\n .equals(name)) {\n httpConfig.setContextPath(getTextContent(node));\n } else if (ServerConfigOptions.MasterServerConfigOptions.ENABLE_HTTP\n .key()\n .equals(name)) {\n httpConfig.setEnabled(getBooleanValue(getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.ENABLE_DYNAMIC_PORT\n .key()\n .equals(name)) {\n httpConfig.setEnableDynamicPort(getBooleanValue(getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.PORT_RANGE\n .key()\n .equals(name)) {\n httpConfig.setPortRange(\n getIntegerValue(\n ServerConfigOptions.MasterServerConfigOptions.PORT_RANGE.key(),\n getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.ENABLE_HTTPS\n .key()\n .equals(name)) {\n httpConfig.setEnableHttps(getBooleanValue(getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.HTTPS_PORT\n .key()\n .equals(name)) {\n httpConfig.setHttpsPort(\n getIntegerValue(\n ServerConfigOptions.MasterServerConfigOptions.HTTPS_PORT.key(),\n getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.KEY_STORE_PATH\n .key()\n .equals(name)) {\n httpConfig.setKeyStorePath(getTextContent(node));\n } else if (ServerConfigOptions.MasterServerConfigOptions.KEY_STORE_PASSWORD\n .key()\n .equals(name)) {\n httpConfig.setKeyStorePassword(getTextContent(node));\n } else if (ServerConfigOptions.MasterServerConfigOptions.KEY_MANAGER_PASSWORD\n .key()\n .equals(name)) {\n httpConfig.setKeyManagerPassword(getTextContent(node));\n } else if (ServerConfigOptions.MasterServerConfigOptions.TRUST_STORE_PATH\n .key()\n .equals(name)) {\n httpConfig.setTrustStorePath(getTextContent(node));\n } else if (ServerConfigOptions.MasterServerConfigOptions.TRUST_STORE_PASSWORD\n .key()\n .equals(name)) {\n httpConfig.setTrustStorePassword(getTextContent(node));\n } else {\n LOGGER.warning(\"Unrecognized element: \" + name);\n }\n }\n return httpConfig;\n }\n}" +pre_fix = " private HttpConfig parseHttpConfig(Node httpNode) {\n HttpConfig httpConfig = new HttpConfig();\n for (Node node : childElements(httpNode)) {\n String name = cleanNodeName(node);\n if (ServerConfigOptions.MasterServerConfigOptions.PORT.key().equals(name)) {\n httpConfig.setPort(\n getIntegerValue(\n ServerConfigOptions.MasterServerConfigOptions.PORT.key(),\n getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.CONTEXT_PATH\n .key()\n .equals(name)) {\n httpConfig.setContextPath(getTextContent(node));\n } else if (ServerConfigOptions.MasterServerConfigOptions.ENABLE_HTTP\n .key()\n .equals(name)) {\n httpConfig.setEnabled(getBooleanValue(getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.ENABLE_DYNAMIC_PORT\n .key()\n .equals(name)) {\n httpConfig.setEnableDynamicPort(getBooleanValue(getTextContent(node)));\n } else if (ServerConfigOptions.MasterServerConfigOptions.PORT_RANGE\n .key()\n .equals(name)) {\n httpConfig.setPortRange(\n getIntegerValue(\n ServerConfigOptions.MasterServerConfigOptions.PORT_RANGE.key(),\n getTextContent(node)));\n } else {\n LOGGER.warning(\"Unrecognized element: \" + name);\n }\n }\n return httpConfig;\n }\n}" +repo = "apache/seatunnel" +url = "https://github.com/apache/seatunnel.git" + +[[case]] +advisory = "GHSA-9x53-gr7p-4qf5" +advisory_text = "Apache SeaTunnel: Unauthenticated insecure access\n\n# Summary\n\nUnauthorized users can perform Arbitrary File Read and Deserialization\nattack by submit job using restful api-v1.\n\n# Details\nUnauthorized users can access `/hazelcast/rest/maps/submit-job` to submit\njob.\nAn attacker can set extra params in mysql url to perform Arbitrary File\nRead and Deserialization attack.\n\nThis issue affects Apache SeaTunnel: <=2.3.10\n\n# Fixed\n\nUsers are recommended to upgrade to version 2.3.11, and enable restful api-v2 & open https two-way authentication , which fixes the issue." +commit = "53325aa3e76e3939f41a4bf3eaaf3ee56f13f311" +cwe = "CWE-306" +family = "access_control" +function = "JettyService" +function_lines = [[88, 100]] +id = "apache-seatunnel-aff20b2911a11f57" +language = "java" +method = "fix_site" +parent = "8a9db476bdc37d5e4079491bdb7092b892a17a7b" +path = "seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/JettyService.java" +post_fix = " public JettyService(NodeEngineImpl nodeEngine, SeaTunnelConfig seaTunnelConfig) {\n this.nodeEngine = nodeEngine;\n this.seaTunnelConfig = seaTunnelConfig;\n int port = seaTunnelConfig.getEngineConfig().getHttpConfig().getPort();\n if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnableDynamicPort()) {\n port =\n chooseAppropriatePort(\n port, seaTunnelConfig.getEngineConfig().getHttpConfig().getPortRange());\n }\n log.info(\"SeaTunnel REST service will start on port {}\", port);\n this.server = new Server();\n\n if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnabled()) {\n // Enable http\n ServerConnector httpConnector = new ServerConnector(server);\n httpConnector.setPort(port);\n server.addConnector(httpConnector);\n }\n\n if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnableHttps()) {\n // Enable https\n log.info(\"SeaTunnel REST service will start on https port {}\", port);\n enableHttps(server, seaTunnelConfig);\n }\n }\n" +pre_fix = " public JettyService(NodeEngineImpl nodeEngine, SeaTunnelConfig seaTunnelConfig) {\n this.nodeEngine = nodeEngine;\n this.seaTunnelConfig = seaTunnelConfig;\n int port = seaTunnelConfig.getEngineConfig().getHttpConfig().getPort();\n if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnableDynamicPort()) {\n port =\n chooseAppropriatePort(\n port, seaTunnelConfig.getEngineConfig().getHttpConfig().getPortRange());\n }\n log.info(\"SeaTunnel REST service will start on port {}\", port);\n this.server = new Server(port);\n }\n" +repo = "apache/seatunnel" +url = "https://github.com/apache/seatunnel.git" + +[[case]] +advisory = "GHSA-9x53-gr7p-4qf5" +advisory_text = "Apache SeaTunnel: Unauthenticated insecure access\n\n# Summary\n\nUnauthorized users can perform Arbitrary File Read and Deserialization\nattack by submit job using restful api-v1.\n\n# Details\nUnauthorized users can access `/hazelcast/rest/maps/submit-job` to submit\njob.\nAn attacker can set extra params in mysql url to perform Arbitrary File\nRead and Deserialization attack.\n\nThis issue affects Apache SeaTunnel: <=2.3.10\n\n# Fixed\n\nUsers are recommended to upgrade to version 2.3.11, and enable restful api-v2 & open https two-way authentication , which fixes the issue." +commit = "53325aa3e76e3939f41a4bf3eaaf3ee56f13f311" +cwe = "CWE-306" +family = "access_control" +function = "init" +function_lines = [[119, 164]] +id = "apache-seatunnel-c1d9182bb687ec27" +language = "java" +method = "fix_site" +parent = "8a9db476bdc37d5e4079491bdb7092b892a17a7b" +path = "seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/SeaTunnelServer.java" +post_fix = " public void init(NodeEngine engine, Properties hzProperties) {\n this.nodeEngine = (NodeEngineImpl) engine;\n // TODO Determine whether to execute there method on the master node according to the deploy\n // type\n\n classLoaderService =\n new DefaultClassLoaderService(\n seaTunnelConfig.getEngineConfig().isClassloaderCacheMode(), nodeEngine);\n\n eventService = new EventService(nodeEngine);\n\n if (EngineConfig.ClusterRole.MASTER_AND_WORKER.ordinal()\n == seaTunnelConfig.getEngineConfig().getClusterRole().ordinal()) {\n startWorker();\n startMaster();\n\n } else if (EngineConfig.ClusterRole.WORKER.ordinal()\n == seaTunnelConfig.getEngineConfig().getClusterRole().ordinal()) {\n startWorker();\n } else {\n startMaster();\n }\n\n seaTunnelHealthMonitor = new SeaTunnelHealthMonitor(((NodeEngineImpl) engine).getNode());\n\n // task log manager service\n if (seaTunnelConfig.getEngineConfig().getTelemetryConfig() != null\n && seaTunnelConfig.getEngineConfig().getTelemetryConfig().getLogs() != null\n && seaTunnelConfig.getEngineConfig().getTelemetryConfig().getLogs().isEnabled()) {\n taskLogManagerService =\n new TaskLogManagerService(\n seaTunnelConfig.getEngineConfig().getTelemetryConfig().getLogs());\n taskLogManagerService.initClean();\n }\n\n // Start Jetty server\n if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnabled()\n || seaTunnelConfig.getEngineConfig().getHttpConfig().isEnableHttps()) {\n jettyService = new JettyService(nodeEngine, seaTunnelConfig);\n jettyService.createJettyServer();\n }\n\n // a trick way to fix StatisticsDataReferenceCleaner thread class loader leak.\n // see https://issues.apache.org/jira/browse/HADOOP-19049\n FileSystem.Statistics statistics = new FileSystem.Statistics(\"SeaTunnel\");\n }\n" +pre_fix = " public void init(NodeEngine engine, Properties hzProperties) {\n this.nodeEngine = (NodeEngineImpl) engine;\n // TODO Determine whether to execute there method on the master node according to the deploy\n // type\n\n classLoaderService =\n new DefaultClassLoaderService(\n seaTunnelConfig.getEngineConfig().isClassloaderCacheMode(), nodeEngine);\n\n eventService = new EventService(nodeEngine);\n\n if (EngineConfig.ClusterRole.MASTER_AND_WORKER.ordinal()\n == seaTunnelConfig.getEngineConfig().getClusterRole().ordinal()) {\n startWorker();\n startMaster();\n\n } else if (EngineConfig.ClusterRole.WORKER.ordinal()\n == seaTunnelConfig.getEngineConfig().getClusterRole().ordinal()) {\n startWorker();\n } else {\n startMaster();\n }\n\n seaTunnelHealthMonitor = new SeaTunnelHealthMonitor(((NodeEngineImpl) engine).getNode());\n\n // task log manager service\n if (seaTunnelConfig.getEngineConfig().getTelemetryConfig() != null\n && seaTunnelConfig.getEngineConfig().getTelemetryConfig().getLogs() != null\n && seaTunnelConfig.getEngineConfig().getTelemetryConfig().getLogs().isEnabled()) {\n taskLogManagerService =\n new TaskLogManagerService(\n seaTunnelConfig.getEngineConfig().getTelemetryConfig().getLogs());\n taskLogManagerService.initClean();\n }\n\n // Start Jetty server\n if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnabled()) {\n jettyService = new JettyService(nodeEngine, seaTunnelConfig);\n jettyService.createJettyServer();\n }\n\n // a trick way to fix StatisticsDataReferenceCleaner thread class loader leak.\n // see https://issues.apache.org/jira/browse/HADOOP-19049\n FileSystem.Statistics statistics = new FileSystem.Statistics(\"SeaTunnel\");\n }\n" +repo = "apache/seatunnel" +url = "https://github.com/apache/seatunnel.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "HttpSyncDataService" +function_lines = [[100, 106]] +id = "apache-shenyu-08bb00ae847d91de" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/HttpSyncDataService.java" +post_fix = " public HttpSyncDataService(final HttpConfig httpConfig, final PluginDataSubscriber pluginDataSubscriber,\n final List metaDataSubscribers, final List authDataSubscribers) {\n this.httpConfig = httpConfig;\n this.factory = new DataRefreshFactory(pluginDataSubscriber, metaDataSubscribers, authDataSubscribers);\n this.serverList = Lists.newArrayList(Splitter.on(\",\").split(httpConfig.getUrl()));\n this.httpClient = createRestTemplate();\n this.accessToken = new FreshBeanHolder<>(this::doLogin);\n this.start();\n }" +pre_fix = " public HttpSyncDataService(final HttpConfig httpConfig, final PluginDataSubscriber pluginDataSubscriber,\n final List metaDataSubscribers, final List authDataSubscribers) {\n this.factory = new DataRefreshFactory(pluginDataSubscriber, metaDataSubscribers, authDataSubscribers);\n this.serverList = Lists.newArrayList(Splitter.on(\",\").split(httpConfig.getUrl()));\n this.httpClient = createRestTemplate();\n this.start();\n }" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "ruleLog" +function_lines = [[136, 141]] +id = "apache-shenyu-21babb9f9e9ab4ab" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java" +post_fix = " private void ruleLog(final RuleData ruleData, final String pluginName) {\n if (ruleData.getLoged()) {\n LOG.info(\"{} rule success match , rule name :{}\", pluginName, ruleData.getName());\n }\n }\n}" +pre_fix = " private void ruleLog(final RuleData ruleData, final String pluginName) {\n if (Boolean.TRUE.equals(ruleData.getLoged())) {\n LOG.info(\"{} rule success match , rule name :{}\", pluginName, ruleData.getName());\n }\n }\n}" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "onAccessDenied" +function_lines = [[54, 81]] +id = "apache-shenyu-2898cf36f15386c4" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/bean/StatelessAuthFilter.java" +post_fix = " protected boolean onAccessDenied(final ServletRequest servletRequest,\n final ServletResponse servletResponse) throws Exception {\n HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;\n if (StringUtils.equals(HttpMethod.OPTIONS.name(), httpServletRequest.getMethod())) {\n return true;\n }\n\n String tokenValue = httpServletRequest.getHeader(Constants.X_ACCESS_TOKEN);\n if (StringUtils.isBlank(tokenValue)) {\n LOG.error(\"token is null.\");\n unionFailResponse(servletResponse);\n return false;\n }\n\n StatelessToken token = new StatelessToken(tokenValue);\n\n Subject subject = getSubject(servletRequest, servletResponse);\n\n try {\n subject.login(token);\n } catch (Exception e) {\n LOG.error(\"token is warning. token : {}.\", tokenValue, e);\n unionFailResponse(servletResponse);\n return false;\n }\n\n return true;\n }" +pre_fix = " protected boolean onAccessDenied(final ServletRequest servletRequest,\n final ServletResponse servletResponse) throws Exception {\n HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;\n if (StringUtils.equals(HttpMethod.OPTIONS.name(), httpServletRequest.getMethod())) {\n return true;\n }\n\n String tokenValue = httpServletRequest.getHeader(HEAD_TOKEN);\n if (StringUtils.isBlank(tokenValue)) {\n LOG.error(\"token is null.\");\n unionFailResponse(servletResponse);\n return false;\n }\n\n StatelessToken token = new StatelessToken(tokenValue);\n\n Subject subject = getSubject(servletRequest, servletResponse);\n\n try {\n subject.login(token);\n } catch (Exception e) {\n LOG.error(\"token is warning. token : {}.\", tokenValue, e);\n unionFailResponse(servletResponse);\n return false;\n }\n\n return true;\n }" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "ShenyuClientShutdownHook" +function_lines = [[54, 66]] +id = "apache-shenyu-3392773569911d4d" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/shutdown/ShenyuClientShutdownHook.java" +post_fix = " public ShenyuClientShutdownHook() {\n }\n" +pre_fix = " public ShenyuClientShutdownHook(final ShenyuClientRegisterRepository repository, final ShenyuRegisterCenterConfig config) {\n String name = hookNamePrefix + \"-\" + hookId.incrementAndGet();\n Runtime.getRuntime().addShutdownHook(new Thread(repository::close, name));\n LOG.info(\"Add hook {}\", name);\n ShenyuClientShutdownHook.props = config.getProps();\n }\n\n /**\n * Add shenyu client shutdown hook.\n *\n * @param result ShenyuClientRegisterRepository\n * @param props Properties\n */" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "init" +function_lines = [[58, 67]] +id = "apache-shenyu-48cd759b689a7006" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java" +post_fix = " public void init(final ShenyuRegisterCenterConfig config) {\n this.username = config.getProps().getProperty(Constants.USER_NAME);\n this.password = config.getProps().getProperty(Constants.PASS_WORD);\n this.serverList = Lists.newArrayList(Splitter.on(\",\").split(config.getServerLists()));\n this.getAccessToken().ifPresent(V -> this.accessToken = String.valueOf(V));\n }\n\n /**\n * Persist uri.\n *\n * @param registerDTO the register dto\n */\n @Override" +pre_fix = " public void init(final ShenyuRegisterCenterConfig config) {\n this.serverList = Lists.newArrayList(Splitter.on(\",\").split(config.getServerLists()));\n }\n \n /**\n * Persist uri.\n *\n * @param registerDTO the register dto\n */\n @Override" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "doRegister" +function_lines = [[46, 54]] +id = "apache-shenyu-5aec8e2616aa9218" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/utils/RegisterUtils.java" +post_fix = " public static void doRegister(final String json, final String url, final String type, final String accessToken) throws IOException {\n if (StringUtils.isEmpty(accessToken)) {\n LOGGER.error(\"{} client register error accessToken is null, please check the config : {} \", type, json);\n return;\n }\n Headers headers = new Headers.Builder().add(Constants.X_ACCESS_TOKEN, accessToken).build();\n String result = OkHttpTools.getInstance().post(url, json, headers);\n if (Objects.equals(SUCCESS, result)) {\n LOGGER.info(\"{} client register success: {} \", type, json);\n } else {\n LOGGER.error(\"{} client register error: {} \", type, json);\n }\n }\n\n /**\n * Do register.\n *\n * @param json the json\n * @param url the url\n * @param type the type\n * @throws IOException the io exception\n */" +pre_fix = " public static void doRegister(final String json, final String url, final String type) throws IOException {\n String result = OkHttpTools.getInstance().post(url, json);\n if (Objects.equals(SUCCESS, result)) {\n LOGGER.info(\"{} client register success: {} \", type, json);\n } else {\n LOGGER.error(\"{} client register error: {} \", type, json);\n }\n }\n}" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "doFetchGroupConfig" +function_lines = [[147, 178]] +id = "apache-shenyu-71dedd5f120287fd" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/HttpSyncDataService.java" +post_fix = " private void doFetchGroupConfig(final String server, final ConfigGroupEnum... groups) {\n StringBuilder params = new StringBuilder();\n for (ConfigGroupEnum groupKey : groups) {\n params.append(\"groupKeys\").append(\"=\").append(groupKey.name()).append(\"&\");\n }\n String url = server + Constants.SHENYU_ADMIN_PATH_CONFIGS_FETCH + \"?\" + StringUtils.removeEnd(params.toString(), \"&\");\n LOG.info(\"request configs: [{}]\", url);\n String json;\n try {\n Optional token = accessToken.apply(server);\n if (!token.isPresent()) {\n throw new ShenyuException(\"get token from server : [\" + server + \" ] error\");\n }\n HttpHeaders headers = new HttpHeaders();\n headers.set(Constants.X_ACCESS_TOKEN, String.valueOf(token.get()));\n HttpEntity httpEntity = new HttpEntity<>(headers);\n json = this.httpClient.exchange(url, HttpMethod.GET, httpEntity, String.class).getBody();\n } catch (RestClientException e) {\n String message = String.format(\"fetch config fail from server[%s], %s\", url, e.getMessage());\n LOG.warn(message);\n throw new ShenyuException(message, e);\n }\n // update local cache\n boolean updated = this.updateCacheWithJson(json);\n if (updated) {\n LOG.info(\"get latest configs: [{}]\", json);\n return;\n }\n // not updated. it is likely that the current config server has not been updated yet. wait a moment.\n LOG.info(\"The config of the server[{}] has not been updated or is out of date. Wait for 30s to listen for changes again.\", server);\n ThreadUtils.sleep(TimeUnit.SECONDS, 30);\n }\n\n /**\n * update local cache.\n *\n * @param json the response from config server.\n * @return true: the local cache was updated. false: not updated.\n */" +pre_fix = " private void doFetchGroupConfig(final String server, final ConfigGroupEnum... groups) {\n StringBuilder params = new StringBuilder();\n for (ConfigGroupEnum groupKey : groups) {\n params.append(\"groupKeys\").append(\"=\").append(groupKey.name()).append(\"&\");\n }\n String url = server + SHENYU_ADMIN_PATH_CONFIGS_FETCH + \"?\" + StringUtils.removeEnd(params.toString(), \"&\");\n LOG.info(\"request configs: [{}]\", url);\n String json;\n try {\n json = this.httpClient.getForObject(url, String.class);\n } catch (RestClientException e) {\n String message = String.format(\"fetch config fail from server[%s], %s\", url, e.getMessage());\n LOG.warn(message);\n throw new ShenyuException(message, e);\n }\n // update local cache\n boolean updated = this.updateCacheWithJson(json);\n if (updated) {\n LOG.info(\"get latest configs: [{}]\", json);\n return;\n }\n // not updated. it is likely that the current config server has not been updated yet. wait a moment.\n LOG.info(\"The config of the server[{}] has not been updated or is out of date. Wait for 30s to listen for changes again.\", server);\n ThreadUtils.sleep(TimeUnit.SECONDS, 30);\n }\n\n /**\n * update local cache.\n *\n * @param json the response from config server.\n * @return true: the local cache was updated. false: not updated.\n */" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "selectorLog" +function_lines = [[130, 135]] +id = "apache-shenyu-86d1b994c1372ebd" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java" +post_fix = " private void selectorLog(final SelectorData selectorData, final String pluginName) {\n if (selectorData.getLogged()) {\n LOG.info(\"{} selector success match , selector name :{}\", pluginName, selectorData.getName());\n }\n }\n" +pre_fix = " private void selectorLog(final SelectorData selectorData, final String pluginName) {\n if (Boolean.TRUE.equals(selectorData.getLogged())) {\n LOG.info(\"{} selector success match , selector name :{}\", pluginName, selectorData.getName());\n }\n }\n" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "doLongPolling" +function_lines = [[186, 221]] +id = "apache-shenyu-8cbc4df3ac5b6e0b" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/HttpSyncDataService.java" +post_fix = " private void doLongPolling(final String server) {\n Optional token = accessToken.apply(server);\n if (!token.isPresent()) {\n throw new ShenyuException(\"get token from server : [\" + server + \" ] error\");\n }\n MultiValueMap params = new LinkedMultiValueMap<>(8);\n for (ConfigGroupEnum group : ConfigGroupEnum.values()) {\n ConfigData cacheConfig = factory.cacheConfigData(group);\n if (cacheConfig != null) {\n String value = String.join(\",\", cacheConfig.getMd5(), String.valueOf(cacheConfig.getLastModifyTime()));\n params.put(group.name(), Lists.newArrayList(value));\n }\n }\n HttpHeaders headers = new HttpHeaders();\n headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n headers.set(Constants.X_ACCESS_TOKEN, String.valueOf(token.get()));\n HttpEntity> httpEntity = new HttpEntity<>(params, headers);\n String listenerUrl = server + Constants.SHENYU_ADMIN_PATH_CONFIGS_LISTENER;\n LOG.debug(\"request listener configs: [{}]\", listenerUrl);\n\n JsonArray groupJson;\n try {\n String json = this.httpClient.postForEntity(listenerUrl, httpEntity, String.class).getBody();\n LOG.debug(\"listener result: [{}]\", json);\n groupJson = GSON.fromJson(json, JsonObject.class).getAsJsonArray(\"data\");\n } catch (RestClientException e) {\n String message = String.format(\"listener configs fail, server:[%s], %s\", server, e.getMessage());\n throw new ShenyuException(message, e);\n }\n\n if (Objects.nonNull(groupJson)) {\n // fetch group configuration async.\n ConfigGroupEnum[] changedGroups = GSON.fromJson(groupJson, ConfigGroupEnum[].class);\n if (ArrayUtils.isNotEmpty(changedGroups)) {\n LOG.info(\"Group config changed: {}\", Arrays.toString(changedGroups));\n this.doFetchGroupConfig(server, changedGroups);\n }\n }\n }\n\n @Override" +pre_fix = " private void doLongPolling(final String server) {\n MultiValueMap params = new LinkedMultiValueMap<>(8);\n for (ConfigGroupEnum group : ConfigGroupEnum.values()) {\n ConfigData cacheConfig = factory.cacheConfigData(group);\n if (cacheConfig != null) {\n String value = String.join(\",\", cacheConfig.getMd5(), String.valueOf(cacheConfig.getLastModifyTime()));\n params.put(group.name(), Lists.newArrayList(value));\n }\n }\n HttpHeaders headers = new HttpHeaders();\n headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n HttpEntity> httpEntity = new HttpEntity<>(params, headers);\n String listenerUrl = server + SHENYU_ADMIN_PATH_CONFIGS_LISTENER;\n LOG.debug(\"request listener configs: [{}]\", listenerUrl);\n\n JsonArray groupJson;\n try {\n String json = this.httpClient.postForEntity(listenerUrl, httpEntity, String.class).getBody();\n LOG.debug(\"listener result: [{}]\", json);\n groupJson = GSON.fromJson(json, JsonObject.class).getAsJsonArray(\"data\");\n } catch (RestClientException e) {\n String message = String.format(\"listener configs fail, server:[%s], %s\", server, e.getMessage());\n throw new ShenyuException(message, e);\n }\n\n if (Objects.nonNull(groupJson)) {\n // fetch group configuration async.\n ConfigGroupEnum[] changedGroups = GSON.fromJson(groupJson, ConfigGroupEnum[].class);\n if (ArrayUtils.isNotEmpty(changedGroups)) {\n LOG.info(\"Group config changed: {}\", Arrays.toString(changedGroups));\n this.doFetchGroupConfig(server, changedGroups);\n }\n }\n }\n\n @Override" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "post" +function_lines = [[67, 75]] +id = "apache-shenyu-9323af96ad3ae2fb" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/utils/OkHttpTools.java" +post_fix = " public String post(final String url, final String json) throws IOException {\n RequestBody body = RequestBody.create(JSON, json);\n Request request = new Request.Builder()\n .url(url)\n .post(body)\n .build();\n return client.newCall(request).execute().body().string();\n }\n\n /**\n * Post string.\n *\n * @param url the url\n * @param json the json\n * @param headers the headers\n * @return the string\n * @throws IOException the io exception\n */" +pre_fix = " public String post(final String url, final String json) throws IOException {\n RequestBody body = RequestBody.create(JSON, json);\n Request request = new Request.Builder()\n .url(url)\n .post(body)\n .build();\n return client.newCall(request).execute().body().string();\n }\n}" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "set" +function_lines = [[67, 76]] +id = "apache-shenyu-b4c7abef3b7d7a60" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/shutdown/ShenyuClientShutdownHook.java" +post_fix = " public static void set(final ShenyuClientRegisterRepository result, final Properties props) {\n String name = String.join(\"-\", hookNamePrefix, String.valueOf(hookId.incrementAndGet()));\n Runtime.getRuntime().addShutdownHook(new Thread(result::close, name));\n LOG.info(\"Add hook {}\", name);\n ShenyuClientShutdownHook.props = props;\n }\n\n /**\n * Delay other shutdown hooks.\n */" +pre_fix = " public static void set(final ShenyuClientRegisterRepository result, final Properties props) {\n String name = hookNamePrefix + \"-\" + hookId.incrementAndGet();\n Runtime.getRuntime().addShutdownHook(new Thread(result::close, name));\n LOG.info(\"Add hook {}\", name);\n ShenyuClientShutdownHook.props = props;\n }\n\n /**\n * Delay other shutdown hooks.\n */" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "persistInterface" +function_lines = [[73, 76]] +id = "apache-shenyu-bb0f638668edb9b3" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java" +post_fix = " public void persistInterface(final MetaDataRegisterDTO metadata) {\n doRegister(metadata, Constants.META_PATH, Constants.META_TYPE);\n }\n" +pre_fix = " public void persistInterface(final MetaDataRegisterDTO metadata) {\n doRegister(metadata, META_PATH, META_TYPE);\n }\n " +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "run" +function_lines = [[240, 263]] +id = "apache-shenyu-d5ae868eba03eee3" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/HttpSyncDataService.java" +post_fix = " public void run() {\n while (RUNNING.get()) {\n int retryTimes = 3;\n for (int time = 1; time <= retryTimes; time++) {\n try {\n //refresh the admin token\n accessToken.doFresh(server);\n doLongPolling(server);\n } catch (Exception e) {\n // print warnning LOG.\n if (time < retryTimes) {\n LOG.warn(\"Long polling failed, tried {} times, {} times left, will be suspended for a while! {}\",\n time, retryTimes - time, e.getMessage());\n ThreadUtils.sleep(TimeUnit.SECONDS, 5);\n continue;\n }\n // print error, then suspended for a while.\n LOG.error(\"Long polling failed, try again after 5 minutes!\", e);\n ThreadUtils.sleep(TimeUnit.MINUTES, 5);\n }\n }\n }\n LOG.warn(\"Stop http long polling.\");\n }\n }\n}" +pre_fix = " public void run() {\n while (RUNNING.get()) {\n int retryTimes = 3;\n for (int time = 1; time <= retryTimes; time++) {\n try {\n doLongPolling(server);\n } catch (Exception e) {\n // print warnning LOG.\n if (time < retryTimes) {\n LOG.warn(\"Long polling failed, tried {} times, {} times left, will be suspended for a while! {}\",\n time, retryTimes - time, e.getMessage());\n ThreadUtils.sleep(TimeUnit.SECONDS, 5);\n continue;\n }\n // print error, then suspended for a while.\n LOG.error(\"Long polling failed, try again after 5 minutes!\", e);\n ThreadUtils.sleep(TimeUnit.MINUTES, 5);\n }\n }\n }\n LOG.warn(\"Stop http long polling.\");\n }\n }\n}" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "persistURI" +function_lines = [[68, 72]] +id = "apache-shenyu-ddf3e7dd3e6d25df" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java" +post_fix = " public void persistURI(final URIRegisterDTO registerDTO) {\n doRegister(registerDTO, Constants.URI_PATH, Constants.URI);\n }\n\n @Override" +pre_fix = " public void persistURI(final URIRegisterDTO registerDTO) {\n doRegister(registerDTO, URI_PATH, Constants.URI);\n }\n \n @Override" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "HttpClientRegisterRepository" +function_lines = [[53, 57]] +id = "apache-shenyu-f40519f074a1b7cd" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java" +post_fix = " public HttpClientRegisterRepository() {\n }\n" +pre_fix = " public HttpClientRegisterRepository(final ShenyuRegisterCenterConfig config) {\n init(config);\n }\n\n @Override" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-7rjp-fgwj-47rw" +advisory_text = "Missing authentication in ShenYu\n\nMissing authentication on ShenYu Admin when register by HTTP. This issue affected Apache ShenYu 2.4.0 and 2.4.1." +commit = "9a02215013037e1cc8cd41f216164628a9e9e28f" +cwe = "CWE-306" +family = "access_control" +function = "doRegister" +function_lines = [[77, 87]] +id = "apache-shenyu-f885a44d7a6b41cf" +language = "java" +method = "fix_site" +parent = "6ca007400ebd17eabc2769573c081652cecdf134" +path = "shenyu-register-center/shenyu-register-client/shenyu-register-client-http/src/main/java/org/apache/shenyu/register/client/http/HttpClientRegisterRepository.java" +post_fix = " private void doRegister(final T t, final String path, final String type) {\n for (String server : serverList) {\n try {\n RegisterUtils.doRegister(GsonUtils.getInstance().toJson(t), server.concat(path), type, accessToken);\n return;\n } catch (Exception e) {\n LOGGER.error(\"register admin url :{} is fail, will retry, ex is :{}\", server, e);\n }\n }\n }\n}" +pre_fix = " private void doRegister(final T t, final String path, final String type) {\n for (String server : serverList) {\n try {\n RegisterUtils.doRegister(GsonUtils.getInstance().toJson(t), server + path, type);\n return;\n } catch (Exception e) {\n LOGGER.error(\"register admin url :{} is fail, will retry, ex is :{}\", server, e);\n }\n }\n }\n}" +repo = "apache/shenyu" +url = "https://github.com/apache/shenyu.git" + +[[case]] +advisory = "GHSA-x4m5-4cw8-vc44" +advisory_text = "axios-cache-interceptor Vulnerable to Cache Poisoning via Ignored HTTP Vary Header\n\n## Summary\n\nWhen a server calls an upstream service using different auth tokens, axios-cache-interceptor returns incorrect cached responses, leading to authorization bypass.\n\n## Details\n\nThe cache key is generated only from the URL, ignoring request headers like `Authorization`. When the server responds with `Vary: Authorization` (indicating the response varies by auth token), the library ignores this, causing all requests to share the same cache regardless of authorization.\n\n## Impact\n\n**Affected:** Server-side applications (APIs, proxies, backend services) that:\n\n- Use axios-cache-interceptor to cache requests to upstream services\n- Handle requests from multiple users with different auth tokens\n- Upstream services replies on `Vary` to differentiate caches\n\n**Not affected:** Browser/client-side applications (single user per browser session).\n\nServices using different auth tokens to call upstream services will return incorrect cached data, bypassing authorization checks and leaking user data across different authenticated sessions.\n\n## Solution\n\nAfter `v1.11.1`, automatic `Vary` header support is now enabled by default.\n\nWhen server responds with `Vary: Authorization`, cache keys now include the authorization header value. Each user gets their own cache.\n\n```js\n// v1.11.1+ (automatic, no config needed)\n// User 123: key = hash(url + {authorization: 'Bearer 123'})\n// User 456: key = hash(url + {authorization: 'Bearer 456'})\n// ✓ Different caches, no poisoning\n```\n\n## Remediation\n\nUpgrade to v1.11.1 or later. _No code changes required, protection is automatic_\n\n\n## Proof of Concept\n\n```js\nconst http = require('node:http');\nconst axios = require('axios');\nconst { setupCache } = require('axios-cache-interceptor');\n\n// Server that returns different responses based on Authorization\nconst server = http.createServer((req, res) => {\n const auth = req.headers.authorization;\n\n res.setHeader('Vary', 'Authorization');\n\n if (auth === 'Bearer 123') {\n res.write('Hello, user 123!');\n } else if (auth === 'Bearer 456') {\n res.write('Hello, user 456!');\n } else {\n res.write('Unknown');\n }\n\n res.end();\n});\n\nserver.listen(5000);\n\n// Client making requests with different tokens\nconst cachedAxios = setupCache(axios.create());\n\nconst server2 = http.createServer(async (_req, res) => {\n const authHeader =\n Math.random() < 0.5 ? 'Bearer 123' : 'Bearer 456';\n\n const response = await cachedAxios.get('http://localhost:5000', {\n headers: { Authorization: authHeader }\n });\n\n console.log({\n response: response.data,\n cached: response.cached,\n auth: authHeader\n });\n res.write(response.data);\n res.end();\n});\n\nserver2.listen(5001);\n\n// Trigger 10 requests\nPromise.all(\n Array.from({ length: 10 }, () =>\n axios.get('http://localhost:5001').catch(console.error)\n )\n).finally(() => {\n server.close();\n server2.close();\n});\n```\n\nAll 10 responses return \"Hello, user 123!\" even when using \"Bearer 456\" - users receive each other's cached data." +commit = "49a808059dfc081b9cc23d48f243d55dfce15f01" +cwe = "CWE-639" +family = "access_control" +function = "defaultRequestInterceptor" +function_lines = [[16, 390]] +id = "arthurfiorette-axios-cache-interceptor-b6059ee192dd17ef" +language = "typescript" +method = "fix_site" +parent = "f88d836f0895dec621b84793ff78564873bc2e6c" +path = "src/interceptors/request.ts" +post_fix = "export function defaultRequestInterceptor(axios: AxiosCacheInstance): RequestInterceptor {\n const onFulfilled: RequestInterceptor['onFulfilled'] = async (config) => {\n config.id = axios.generateKey(config, {\n vary:\n config.cache && Array.isArray(config.cache.vary)\n ? extractHeaders(config.headers, config.cache.vary)\n : undefined\n });\n\n if (config.cache === false) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Cache disabled: config.cache === false'\n });\n }\n\n return config;\n }\n\n // merge defaults with per request configuration\n config.cache = { ...axios.defaults.cache, ...config.cache };\n\n // Check if cache is disabled via enabled flag\n if (config.cache.enabled === false) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Cache disabled: config.cache.enabled === false'\n });\n }\n\n return config;\n }\n\n // ignoreUrls (blacklist)\n if (\n typeof config.cache.cachePredicate === 'object' &&\n config.cache.cachePredicate.ignoreUrls &&\n config.url\n ) {\n for (const url of config.cache.cachePredicate.ignoreUrls) {\n if (regexOrStringMatch(url, config.url)) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `URL ignored: matches ignoreUrls pattern`,\n data: { url: config.url, pattern: url }\n });\n }\n\n return config;\n }\n }\n }\n\n // allowUrls\n if (\n typeof config.cache.cachePredicate === 'object' &&\n config.cache.cachePredicate.allowUrls &&\n config.url\n ) {\n let matched = false;\n\n for (const url of config.cache.cachePredicate.allowUrls) {\n if (regexOrStringMatch(url, config.url)) {\n matched = true;\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `URL allowed: matches allowUrls pattern`,\n data: { url: config.url, pattern: url }\n });\n }\n break;\n }\n }\n\n if (!matched) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `URL rejected: not in allowUrls`,\n data: { url: config.url, allowUrls: config.cache.cachePredicate.allowUrls }\n });\n }\n return config;\n }\n }\n\n // Applies sufficient headers to prevent other cache systems to work along with this one\n //\n // Its currently used before isMethodIn because if the isMethodIn returns false, the request\n // shouldn't be cached an therefore neither in the browser.\n // https://stackoverflow.com/a/2068407\n if (config.cache.cacheTakeover) {\n config.headers.set(\n Header.CacheControl,\n 'no-cache, no-store, must-revalidate, max-age=0',\n false\n );\n config.headers.set(Header.Pragma, 'no-cache', false);\n config.headers.set(Header.Expires, '0', false);\n }\n\n if (!isMethodIn(config.method, config.cache.methods)) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `Method ${config.method} not cacheable (allowed: ${config.cache.methods})`\n });\n }\n\n return config;\n }\n\n // Assumes that the storage handled staled responses\n let cache = await axios.storage.get(config.id, config);\n const overrideCache = config.cache.override;\n\n // Checks for vary mismatches in cached responses before proceeding\n // If a vary mismatch is detected, it will generate a new key based on the\n // current request headers and re-fetch the cache.\n if (\n // Vary enabled\n config.cache.vary !== false &&\n // Had vary headers in cached response (cached or stale)\n cache.data?.meta?.vary &&\n // Previous response had Vary header to use\n cache.data.headers[Header.Vary]\n ) {\n const vary = Array.isArray(config.cache.vary)\n ? config.cache.vary\n : parseVary(cache.data.headers[Header.Vary]);\n\n // Compares current request headers with cached vary headers (meta.vary)\n if (vary && vary !== '*' && !compareVary(vary, cache.data.meta?.vary, config.headers)) {\n // Generate base key without id field (otherwise returns config.id)\n const newKey = axios.generateKey(\n { ...config, id: undefined },\n { vary: extractHeaders(config.headers, vary) }\n );\n\n // If ends up being a new key, change the cache to the new one\n if (config.id !== newKey) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Vary mismatch: switching to vary-aware key',\n data: { oldKey: config.id, newKey }\n });\n }\n\n config.id = newKey;\n cache = await axios.storage.get(newKey, config);\n }\n }\n }\n\n // Not cached, continue the request, and mark it as fetching\n // biome-ignore lint/suspicious/noConfusingLabels: required to break condition in simultaneous accesses\n ignoreAndRequest: if (\n cache.state === 'empty' ||\n cache.state === 'stale' ||\n cache.state === 'must-revalidate' ||\n overrideCache\n ) {\n // This checks for simultaneous access to a new key. The js event loop jumps on the\n // first await statement, so the second (asynchronous call) request may have already\n // started executing.\n if (axios.waiting.has(config.id) && !overrideCache) {\n cache = await axios.storage.get(config.id, config);\n\n // This check is required when a request has it own cache deleted manually, lets\n // say by a `axios.storage.delete(key)` and has a concurrent loading request.\n // Because in this case, the cache will be empty and may still has a pending key\n // on waiting map.\n if (cache.state !== 'empty' && cache.state !== 'must-revalidate') {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request found, reusing result'\n });\n }\n\n break ignoreAndRequest;\n }\n }\n\n // Create a deferred to resolve other requests for the same key when it's completed\n const def = deferred();\n axios.waiting.set(config.id, def);\n\n // Adds a default reject handler to catch when the request gets aborted without\n // others waiting for it.\n def.catch(() => undefined);\n\n await axios.storage.set(\n config.id,\n {\n state: 'loading',\n previous: overrideCache\n ? // Simply determine if the request is stale or not\n // based if it had previous data or not\n cache.data\n ? 'stale'\n : 'empty'\n : // Typescript doesn't know that cache.state here can only be 'empty' or 'stale'\n (cache.state as 'stale' | 'must-revalidate'),\n\n data: cache.data as any,\n\n // If the cache is empty and asked to override it, use the current timestamp\n createdAt: overrideCache && !cache.createdAt ? Date.now() : (cache.createdAt as any)\n },\n config\n );\n\n // Skip adding conditional headers (If-None-Match, If-Modified-Since) when override is true.\n // The override option is meant to bypass cache and get fresh data, not revalidate existing cache.\n // Adding conditional headers would cause the server to return 304 Not Modified instead of fresh data.\n if ((cache.state === 'stale' || cache.state === 'must-revalidate') && !overrideCache) {\n updateStaleRequest(cache, { ...config, cache: config.cache });\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Stale revalidation: added conditional headers (If-None-Match/If-Modified-Since)'\n });\n }\n }\n\n config.validateStatus = createValidateStatus(config.validateStatus);\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Making network request',\n data: { overrideCache, cacheState: cache.state }\n });\n }\n\n // Hydrates any UI temporarily, if cache is available\n if (cache.state === 'stale' || (cache.data && cache.state !== 'must-revalidate')) {\n await config.cache.hydrate?.(cache);\n }\n\n return config;\n }\n\n let cachedResponse: CachedResponse;\n\n if (cache.state === 'loading') {\n const deferred = axios.waiting.get(config.id);\n\n // The deferred may not exists when the process is using a persistent\n // storage and cancelled in the middle of a request, this would result in\n // a pending loading state in the storage but no current promises to resolve\n if (!deferred) {\n // Hydrates any UI temporarily, if cache is available\n if (cache.data) {\n await config.cache.hydrate?.(cache);\n }\n\n return config;\n }\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request detected, waiting...'\n });\n }\n\n try {\n // Deferred can't reuse the value because the user's storage might clone\n // or mutate the value, so we need to ask it again.\n // For example with memoryStorage + cloneData\n await deferred;\n const state = await axios.storage.get(config.id, config);\n\n // This is a cache mismatch and should never happen, but in case it does,\n // we need to redo the request all over again.\n /* c8 ignore start */\n if (!state.data) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request completed without data, retrying'\n });\n }\n\n return onFulfilled!(config);\n }\n /* c8 ignore end */\n\n // After waiting, check if this request's vary headers match the cached variant\n // If mismatch, don't use the cache - make own request to prevent cache poisoning\n if (\n config.cache.vary !== false &&\n state.data.meta?.vary &&\n state.data.headers[Header.Vary]\n ) {\n const vary = Array.isArray(config.cache.vary)\n ? config.cache.vary\n : parseVary(state.data.headers[Header.Vary]);\n\n // Compare vary headers - if mismatch, make own request\n if (vary && vary !== '*' && !compareVary(vary, state.data.meta.vary, config.headers)) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Vary mismatch after concurrent request, making own request',\n data: {\n cachedVary: state.data.meta.vary,\n currentVary: extractHeaders(config.headers, vary)\n }\n });\n }\n\n // Don't use cached response - rerun interceptor logic but with new key\n return onFulfilled!(config);\n }\n }\n\n cachedResponse = state.data;\n } catch (err) {\n // The deferred was rejected by the first request that encountered an error.\n // All deduplicated requests waiting on this deferred should fail with the same error\n // to maintain consistency and prevent multiple network retries for the same resource.\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request failed, propagating error',\n data: err\n });\n }\n\n throw err;\n }\n } else {\n cachedResponse = cache.data;\n }\n\n // The cached data is already transformed after receiving the response from the server.\n // Reapplying the transformation on the transformed data will have an unintended effect.\n // Since the cached data is already in the desired format, there is no need to apply the transformation function again.\n config.transformResponse = undefined;\n\n // Even though the response interceptor receives this one from here,\n // it has been configured to ignore cached responses = true\n config.adapter = function cachedAdapter(): Promise {\n return Promise.resolve({\n config,\n data: cachedResponse.data,\n headers: cachedResponse.headers,\n status: cachedResponse.status,\n statusText: cachedResponse.statusText,\n cached: true,\n stale: (cache as LoadingStorageValue).previous === 'stale',\n id: config.id!\n });\n };\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Using cached response'\n });\n }\n\n return config;\n };\n\n return {\n onFulfilled\n };\n}" +pre_fix = "export function defaultRequestInterceptor(axios: AxiosCacheInstance): RequestInterceptor {\n const onFulfilled: RequestInterceptor['onFulfilled'] = async (config) => {\n config.id = axios.generateKey(config, {\n vary:\n config.cache && Array.isArray(config.cache.vary)\n ? extractHeaders(config.headers, config.cache.vary)\n : undefined\n });\n\n if (config.cache === false) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Cache disabled: config.cache === false'\n });\n }\n\n return config;\n }\n\n // merge defaults with per request configuration\n config.cache = { ...axios.defaults.cache, ...config.cache };\n\n // Check if cache is disabled via enabled flag\n if (config.cache.enabled === false) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Cache disabled: config.cache.enabled === false'\n });\n }\n\n return config;\n }\n\n // ignoreUrls (blacklist)\n if (\n typeof config.cache.cachePredicate === 'object' &&\n config.cache.cachePredicate.ignoreUrls &&\n config.url\n ) {\n for (const url of config.cache.cachePredicate.ignoreUrls) {\n if (regexOrStringMatch(url, config.url)) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `URL ignored: matches ignoreUrls pattern`,\n data: { url: config.url, pattern: url }\n });\n }\n\n return config;\n }\n }\n }\n\n // allowUrls\n if (\n typeof config.cache.cachePredicate === 'object' &&\n config.cache.cachePredicate.allowUrls &&\n config.url\n ) {\n let matched = false;\n\n for (const url of config.cache.cachePredicate.allowUrls) {\n if (regexOrStringMatch(url, config.url)) {\n matched = true;\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `URL allowed: matches allowUrls pattern`,\n data: { url: config.url, pattern: url }\n });\n }\n break;\n }\n }\n\n if (!matched) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `URL rejected: not in allowUrls`,\n data: { url: config.url, allowUrls: config.cache.cachePredicate.allowUrls }\n });\n }\n return config;\n }\n }\n\n // Applies sufficient headers to prevent other cache systems to work along with this one\n //\n // Its currently used before isMethodIn because if the isMethodIn returns false, the request\n // shouldn't be cached an therefore neither in the browser.\n // https://stackoverflow.com/a/2068407\n if (config.cache.cacheTakeover) {\n config.headers[Header.CacheControl] ??= 'no-cache, no-store, must-revalidate, max-age=0';\n config.headers[Header.Pragma] ??= 'no-cache';\n config.headers[Header.Expires] ??= '0';\n }\n\n if (!isMethodIn(config.method, config.cache.methods)) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: `Method ${config.method} not cacheable (allowed: ${config.cache.methods})`\n });\n }\n\n return config;\n }\n\n // Assumes that the storage handled staled responses\n let cache = await axios.storage.get(config.id, config);\n const overrideCache = config.cache.override;\n\n // Checks for vary mismatches in cached responses before proceeding\n // If a vary mismatch is detected, it will generate a new key based on the\n // current request headers and re-fetch the cache.\n if (\n // Vary enabled\n config.cache.vary !== false &&\n // Had vary headers in cached response (cached or stale)\n cache.data?.meta?.vary &&\n // Previous response had Vary header to use\n cache.data.headers[Header.Vary]\n ) {\n const vary = Array.isArray(config.cache.vary)\n ? config.cache.vary\n : parseVary(cache.data.headers[Header.Vary]);\n\n // Compares current request headers with cached vary headers (meta.vary)\n if (vary && vary !== '*' && !compareVary(vary, cache.data.meta?.vary, config.headers)) {\n // Generate base key without id field (otherwise returns config.id)\n const newKey = axios.generateKey(\n { ...config, id: undefined },\n { vary: extractHeaders(config.headers, vary) }\n );\n\n // If ends up being a new key, change the cache to the new one\n if (config.id !== newKey) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Vary mismatch: switching to vary-aware key',\n data: { oldKey: config.id, newKey }\n });\n }\n\n config.id = newKey;\n cache = await axios.storage.get(newKey, config);\n }\n }\n }\n\n // Not cached, continue the request, and mark it as fetching\n // biome-ignore lint/suspicious/noConfusingLabels: required to break condition in simultaneous accesses\n ignoreAndRequest: if (\n cache.state === 'empty' ||\n cache.state === 'stale' ||\n cache.state === 'must-revalidate' ||\n overrideCache\n ) {\n // This checks for simultaneous access to a new key. The js event loop jumps on the\n // first await statement, so the second (asynchronous call) request may have already\n // started executing.\n if (axios.waiting.has(config.id) && !overrideCache) {\n cache = await axios.storage.get(config.id, config);\n\n // This check is required when a request has it own cache deleted manually, lets\n // say by a `axios.storage.delete(key)` and has a concurrent loading request.\n // Because in this case, the cache will be empty and may still has a pending key\n // on waiting map.\n if (cache.state !== 'empty' && cache.state !== 'must-revalidate') {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request found, reusing result'\n });\n }\n\n break ignoreAndRequest;\n }\n }\n\n // Create a deferred to resolve other requests for the same key when it's completed\n const def = deferred();\n axios.waiting.set(config.id, def);\n\n // Adds a default reject handler to catch when the request gets aborted without\n // others waiting for it.\n def.catch(() => undefined);\n\n await axios.storage.set(\n config.id,\n {\n state: 'loading',\n previous: overrideCache\n ? // Simply determine if the request is stale or not\n // based if it had previous data or not\n cache.data\n ? 'stale'\n : 'empty'\n : // Typescript doesn't know that cache.state here can only be 'empty' or 'stale'\n (cache.state as 'stale' | 'must-revalidate'),\n\n data: cache.data as any,\n\n // If the cache is empty and asked to override it, use the current timestamp\n createdAt: overrideCache && !cache.createdAt ? Date.now() : (cache.createdAt as any)\n },\n config\n );\n\n // Skip adding conditional headers (If-None-Match, If-Modified-Since) when override is true.\n // The override option is meant to bypass cache and get fresh data, not revalidate existing cache.\n // Adding conditional headers would cause the server to return 304 Not Modified instead of fresh data.\n if ((cache.state === 'stale' || cache.state === 'must-revalidate') && !overrideCache) {\n updateStaleRequest(cache, config as ConfigWithCache);\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Stale revalidation: added conditional headers (If-None-Match/If-Modified-Since)'\n });\n }\n }\n\n config.validateStatus = createValidateStatus(config.validateStatus);\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Making network request',\n data: { overrideCache, cacheState: cache.state }\n });\n }\n\n // Hydrates any UI temporarily, if cache is available\n if (cache.state === 'stale' || (cache.data && cache.state !== 'must-revalidate')) {\n await config.cache.hydrate?.(cache);\n }\n\n return config;\n }\n\n let cachedResponse: CachedResponse;\n\n if (cache.state === 'loading') {\n const deferred = axios.waiting.get(config.id);\n\n // The deferred may not exists when the process is using a persistent\n // storage and cancelled in the middle of a request, this would result in\n // a pending loading state in the storage but no current promises to resolve\n if (!deferred) {\n // Hydrates any UI temporarily, if cache is available\n if (cache.data) {\n await config.cache.hydrate?.(cache);\n }\n\n return config;\n }\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request detected, waiting...'\n });\n }\n\n try {\n // Deferred can't reuse the value because the user's storage might clone\n // or mutate the value, so we need to ask it again.\n // For example with memoryStorage + cloneData\n await deferred;\n const state = await axios.storage.get(config.id, config);\n\n // This is a cache mismatch and should never happen, but in case it does,\n // we need to redo the request all over again.\n /* c8 ignore start */\n if (!state.data) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request completed without data, retrying'\n });\n }\n\n return onFulfilled!(config);\n }\n /* c8 ignore end */\n\n // After waiting, check if this request's vary headers match the cached variant\n // If mismatch, don't use the cache - make own request to prevent cache poisoning\n if (\n config.cache.vary !== false &&\n state.data.meta?.vary &&\n state.data.headers[Header.Vary]\n ) {\n const vary = Array.isArray(config.cache.vary)\n ? config.cache.vary\n : parseVary(state.data.headers[Header.Vary]);\n\n // Compare vary headers - if mismatch, make own request\n if (vary && vary !== '*' && !compareVary(vary, state.data.meta.vary, config.headers)) {\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Vary mismatch after concurrent request, making own request',\n data: {\n cachedVary: state.data.meta.vary,\n currentVary: extractHeaders(config.headers, vary)\n }\n });\n }\n\n // Don't use cached response - rerun interceptor logic but with new key\n return onFulfilled!(config);\n }\n }\n\n cachedResponse = state.data;\n } catch (err) {\n // The deferred was rejected by the first request that encountered an error.\n // All deduplicated requests waiting on this deferred should fail with the same error\n // to maintain consistency and prevent multiple network retries for the same resource.\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Concurrent request failed, propagating error',\n data: err\n });\n }\n\n throw err;\n }\n } else {\n cachedResponse = cache.data;\n }\n\n // The cached data is already transformed after receiving the response from the server.\n // Reapplying the transformation on the transformed data will have an unintended effect.\n // Since the cached data is already in the desired format, there is no need to apply the transformation function again.\n config.transformResponse = undefined;\n\n // Even though the response interceptor receives this one from here,\n // it has been configured to ignore cached responses = true\n config.adapter = function cachedAdapter(): Promise {\n return Promise.resolve({\n config,\n data: cachedResponse.data,\n headers: cachedResponse.headers,\n status: cachedResponse.status,\n statusText: cachedResponse.statusText,\n cached: true,\n stale: (cache as LoadingStorageValue).previous === 'stale',\n id: config.id!\n });\n };\n\n if (__ACI_DEV__) {\n axios.debug({\n id: config.id,\n msg: 'Using cached response'\n });\n }\n\n return config;\n };\n\n return {\n onFulfilled\n };\n}" +repo = "arthurfiorette/axios-cache-interceptor" +url = "https://github.com/arthurfiorette/axios-cache-interceptor.git" + +[[case]] +advisory = "GHSA-x4m5-4cw8-vc44" +advisory_text = "axios-cache-interceptor Vulnerable to Cache Poisoning via Ignored HTTP Vary Header\n\n## Summary\n\nWhen a server calls an upstream service using different auth tokens, axios-cache-interceptor returns incorrect cached responses, leading to authorization bypass.\n\n## Details\n\nThe cache key is generated only from the URL, ignoring request headers like `Authorization`. When the server responds with `Vary: Authorization` (indicating the response varies by auth token), the library ignores this, causing all requests to share the same cache regardless of authorization.\n\n## Impact\n\n**Affected:** Server-side applications (APIs, proxies, backend services) that:\n\n- Use axios-cache-interceptor to cache requests to upstream services\n- Handle requests from multiple users with different auth tokens\n- Upstream services replies on `Vary` to differentiate caches\n\n**Not affected:** Browser/client-side applications (single user per browser session).\n\nServices using different auth tokens to call upstream services will return incorrect cached data, bypassing authorization checks and leaking user data across different authenticated sessions.\n\n## Solution\n\nAfter `v1.11.1`, automatic `Vary` header support is now enabled by default.\n\nWhen server responds with `Vary: Authorization`, cache keys now include the authorization header value. Each user gets their own cache.\n\n```js\n// v1.11.1+ (automatic, no config needed)\n// User 123: key = hash(url + {authorization: 'Bearer 123'})\n// User 456: key = hash(url + {authorization: 'Bearer 456'})\n// ✓ Different caches, no poisoning\n```\n\n## Remediation\n\nUpgrade to v1.11.1 or later. _No code changes required, protection is automatic_\n\n\n## Proof of Concept\n\n```js\nconst http = require('node:http');\nconst axios = require('axios');\nconst { setupCache } = require('axios-cache-interceptor');\n\n// Server that returns different responses based on Authorization\nconst server = http.createServer((req, res) => {\n const auth = req.headers.authorization;\n\n res.setHeader('Vary', 'Authorization');\n\n if (auth === 'Bearer 123') {\n res.write('Hello, user 123!');\n } else if (auth === 'Bearer 456') {\n res.write('Hello, user 456!');\n } else {\n res.write('Unknown');\n }\n\n res.end();\n});\n\nserver.listen(5000);\n\n// Client making requests with different tokens\nconst cachedAxios = setupCache(axios.create());\n\nconst server2 = http.createServer(async (_req, res) => {\n const authHeader =\n Math.random() < 0.5 ? 'Bearer 123' : 'Bearer 456';\n\n const response = await cachedAxios.get('http://localhost:5000', {\n headers: { Authorization: authHeader }\n });\n\n console.log({\n response: response.data,\n cached: response.cached,\n auth: authHeader\n });\n res.write(response.data);\n res.end();\n});\n\nserver2.listen(5001);\n\n// Trigger 10 requests\nPromise.all(\n Array.from({ length: 10 }, () =>\n axios.get('http://localhost:5001').catch(console.error)\n )\n).finally(() => {\n server.close();\n server2.close();\n});\n```\n\nAll 10 responses return \"Hello, user 123!\" even when using \"Bearer 456\" - users receive each other's cached data." +commit = "49a808059dfc081b9cc23d48f243d55dfce15f01" +cwe = "CWE-639" +family = "access_control" +function = "extractHeaders" +function_lines = [[9, 20]] +id = "arthurfiorette-axios-cache-interceptor-e8c5197ddfb12fb5" +language = "typescript" +method = "fix_site" +parent = "f88d836f0895dec621b84793ff78564873bc2e6c" +path = "src/header/extract.ts" +post_fix = "export function extractHeaders(\n requestHeaders: AxiosRequestHeaders | AxiosResponseHeaders,\n headerNames: string[]\n): Record {\n const result: Record = {};\n\n for (const name of headerNames) {\n result[name] = requestHeaders.get(name)?.toString();\n }\n\n return result;\n}" +pre_fix = "export function extractHeaders(\n requestHeaders: Record,\n headerNames: string[]\n): Record {\n const result: Record = {};\n\n for (const name of headerNames) {\n result[name] = String(requestHeaders[name.toLowerCase()] || '');\n }\n\n return result;\n}" +repo = "arthurfiorette/axios-cache-interceptor" +url = "https://github.com/arthurfiorette/axios-cache-interceptor.git" + +[[case]] +advisory = "GHSA-xq8m-7c5p-c2r6" +advisory_text = "Auth0 Next.js SDK has Improper Proxy Cache Lookup\n\n### Description\nIn affected versions of the Next.js SDK, simultaneous requests that trigger a nonce retry may cause the proxy cache fetcher to perform improper lookups for the token request results.\n\n### Which Projects are Affected?\nUsers are affected if they meet all of the following preconditions:\n- Applications using the auth0/nextjs-auth0 SDK, versions 4.12.0 to 4.17.0, and\n- Applications using the proxy handler /me/* and /my-org/* with DPoP enabled.\n\n\n### Affected product and versions\nAuth0/nextjs-auth0 v4.12.0 to 4.17.0\n\n### Resolution\nUpgrade Auth0/nextjs-auth0 version to v4.18.0 or greater\n\n### Acknowledgements\nOkta would like to thank Reynaldo Immanuel for their discovery and responsible disclosure." +commit = "98c36dc306970c2230ea1a32efef431d29b99978" +cwe = "CWE-863" +family = "access_control" +function = "constructor" +function_lines = [[74, 102]] +id = "auth0-nextjs-auth0-02b40a92c3a33337" +language = "typescript" +method = "fix_site" +parent = "b06d30f26a22cd738ddfd5cfdaff8a4faf4328b6" +path = "src/server/auth-client-provider.ts" +post_fix = " constructor(options: AuthClientProviderOptions) {\n this.createAuthClientFactory = options.createAuthClient;\n\n // Initialize LRU caches\n this.domainClients = new LruMap(MAX_DOMAIN_CLIENTS);\n\n // Detect mode and validate configuration\n if (typeof options.domain === \"string\") {\n // Static mode: normalize and validate domain\n this.mode = \"static\";\n const normalized = normalizeDomain(options.domain, {\n allowInsecureRequests: process.env.NODE_ENV === \"test\"\n });\n this.staticDomain = normalized.domain;\n\n // Pre-populate cache with singleton AuthClient for static domain\n const client = this.createAuthClientFactory(this.staticDomain);\n this.domainClients.set(this.staticDomain, client);\n } else if (typeof options.domain === \"function\") {\n // Resolver mode: store resolver function\n this.mode = \"resolver\";\n this.resolver = options.domain;\n } else {\n throw new InvalidConfigurationError(\n \"You must provide either a domain string or a DomainResolver function.\"\n );\n }\n }" +pre_fix = " constructor(options: AuthClientProviderOptions) {\n this.createAuthClientFactory = options.createAuthClient;\n\n // Initialize LRU caches\n this.domainClients = new LruMap(MAX_DOMAIN_CLIENTS);\n this.proxyFetchers = new LruMap(MAX_PROXY_FETCHERS);\n\n // Detect mode and validate configuration\n if (typeof options.domain === \"string\") {\n // Static mode: normalize and validate domain\n this.mode = \"static\";\n const normalized = normalizeDomain(options.domain, {\n allowInsecureRequests: process.env.NODE_ENV === \"test\"\n });\n this.staticDomain = normalized.domain;\n\n // Pre-populate cache with singleton AuthClient for static domain\n const client = this.createAuthClientFactory(this.staticDomain);\n this.domainClients.set(this.staticDomain, client);\n } else if (typeof options.domain === \"function\") {\n // Resolver mode: store resolver function\n this.mode = \"resolver\";\n this.resolver = options.domain;\n } else {\n throw new InvalidConfigurationError(\n \"You must provide either a domain string or a DomainResolver function.\"\n );\n }\n }" +repo = "auth0/nextjs-auth0" +url = "https://github.com/auth0/nextjs-auth0.git" + +[[case]] +advisory = "GHSA-w736-hf9p-qqh3" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.15.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "7de5f5a5929271ab25bce685089eb7ec564dac4b" +cwe = "CWE-862" +family = "access_control" +function = "removeEldestEntry" +function_lines = [[135, 149]] +id = "aws-aws-dynamodb-encryption-java-07cd28b8ecd099ff" +language = "java" +method = "fix_site" +parent = "14c6a95bf91b3b301c1b4f621abb2c97f155bd09" +path = "sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/internal/LRUCache.java" +post_fix = " protected boolean removeEldestEntry(final Entry eldest) {\n return size() > maxSize;\n }\n }\n}" +pre_fix = " protected boolean removeEldestEntry(final Entry eldest) {\n if (size() > maxSize) {\n if (listener != null) {\n listener.onRemoval(eldest);\n }\n return true;\n }\n return false;\n }\n }\n\n public static interface RemovalListener {\n public void onRemoval(Entry entry);\n }\n}" +repo = "aws/aws-dynamodb-encryption-java" +url = "https://github.com/aws/aws-dynamodb-encryption-java.git" + +[[case]] +advisory = "GHSA-w736-hf9p-qqh3" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.15.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "7de5f5a5929271ab25bce685089eb7ec564dac4b" +cwe = "CWE-862" +family = "access_control" +function = "getRandom" +function_lines = [[37, 42]] +id = "aws-aws-dynamodb-encryption-java-57437c3aec27942a" +language = "java" +method = "fix_site" +parent = "14c6a95bf91b3b301c1b4f621abb2c97f155bd09" +path = "sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/internal/Utils.java" +post_fix = " public static byte[] getRandom(int len) {\n final byte[] result = new byte[len];\n getRng().nextBytes(result);\n return result;\n }\n" +pre_fix = " public static byte[] getRandom(int len) {\n final byte[] result = new byte[len];\n getRng().nextBytes(result);\n return result;\n }\n}" +repo = "aws/aws-dynamodb-encryption-java" +url = "https://github.com/aws/aws-dynamodb-encryption-java.git" + +[[case]] +advisory = "GHSA-w736-hf9p-qqh3" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.15.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "7de5f5a5929271ab25bce685089eb7ec564dac4b" +cwe = "CWE-862" +family = "access_control" +function = "LRUCache" +function_lines = [[55, 67]] +id = "aws-aws-dynamodb-encryption-java-73d40fa78fd43933" +language = "java" +method = "fix_site" +parent = "14c6a95bf91b3b301c1b4f621abb2c97f155bd09" +path = "sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/internal/LRUCache.java" +post_fix = " public LRUCache(final int maxSize) {\n if (maxSize < 1) {\n throw new IllegalArgumentException(\"maxSize \" + maxSize + \" must be at least 1\");\n }\n this.maxSize = maxSize;\n map = Collections.synchronizedMap(new LRUHashMap<>(maxSize));\n }\n\n /**\n * Adds an entry to the cache, evicting the earliest entry if necessary.\n */" +pre_fix = " public LRUCache(final int maxSize, final RemovalListener listener) {\n if (maxSize < 1) {\n throw new IllegalArgumentException(\"maxSize \" + maxSize + \" must be at least 1\");\n }\n this.maxSize = maxSize;\n this.listener = listener;\n map = Collections.synchronizedMap(new LRUHashMap(maxSize, listener));\n }\n\n /**\n * @param maxSize\n * the maximum number of entries of the cache\n */" +repo = "aws/aws-dynamodb-encryption-java" +url = "https://github.com/aws/aws-dynamodb-encryption-java.git" + +[[case]] +advisory = "GHSA-w736-hf9p-qqh3" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.15.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "7de5f5a5929271ab25bce685089eb7ec564dac4b" +cwe = "CWE-862" +family = "access_control" +function = "LRUHashMap" +function_lines = [[128, 134]] +id = "aws-aws-dynamodb-encryption-java-b46a82506f9ed435" +language = "java" +method = "fix_site" +parent = "14c6a95bf91b3b301c1b4f621abb2c97f155bd09" +path = "sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/internal/LRUCache.java" +post_fix = " private LRUHashMap(final int maxSize) {\n super(10, 0.75F, true);\n this.maxSize = maxSize;\n }\n\n @Override" +pre_fix = " private LRUHashMap(final int maxSize, final RemovalListener listener) {\n super(10, 0.75F, true);\n this.maxSize = maxSize;\n this.listener = listener;\n }\n\n @Override" +repo = "aws/aws-dynamodb-encryption-java" +url = "https://github.com/aws/aws-dynamodb-encryption-java.git" + +[[case]] +advisory = "GHSA-w736-hf9p-qqh3" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.15.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "7de5f5a5929271ab25bce685089eb7ec564dac4b" +cwe = "CWE-862" +family = "access_control" +function = "unwrapKey" +function_lines = [[158, 170]] +id = "aws-aws-dynamodb-encryption-java-c96110ae95b592d2" +language = "java" +method = "fix_site" +parent = "14c6a95bf91b3b301c1b4f621abb2c97f155bd09" +path = "sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/materials/WrappedRawMaterials.java" +post_fix = " protected SecretKey unwrapKey(Map description, byte[] encryptedKey, String wrappingAlgorithm)\n throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {\n if (unwrappingKey instanceof DelegatedKey) {\n return (SecretKey)((DelegatedKey)unwrappingKey).unwrap(encryptedKey,\n description.get(CONTENT_KEY_ALGORITHM), Cipher.SECRET_KEY, null, wrappingAlgorithm);\n } else {\n Cipher cipher = Cipher.getInstance(wrappingAlgorithm);\n\n // This can be of the form \"AES/256\" as well as \"AES\" e.g.,\n // but we want to set the SecretKey with just \"AES\" in either case\n String[] algPieces = description.get(CONTENT_KEY_ALGORITHM).split(\"/\", 2);\n String contentKeyAlgorithm = algPieces[0];\n\n cipher.init(Cipher.UNWRAP_MODE, unwrappingKey, Utils.getRng());\n return (SecretKey) cipher.unwrap(encryptedKey,\n contentKeyAlgorithm, Cipher.SECRET_KEY);\n }\n }\n " +pre_fix = " protected SecretKey unwrapKey(Map description, byte[] encryptedKey, String wrappingAlgorithm)\n throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {\n if (unwrappingKey instanceof DelegatedKey) {\n return (SecretKey)((DelegatedKey)unwrappingKey).unwrap(encryptedKey,\n description.get(CONTENT_KEY_ALGORITHM), Cipher.SECRET_KEY, null, wrappingAlgorithm);\n } else {\n Cipher cipher = Cipher.getInstance(wrappingAlgorithm);\n cipher.init(Cipher.UNWRAP_MODE, unwrappingKey, Utils.getRng());\n return (SecretKey) cipher.unwrap(encryptedKey,\n description.get(CONTENT_KEY_ALGORITHM), Cipher.SECRET_KEY);\n }\n }\n " +repo = "aws/aws-dynamodb-encryption-java" +url = "https://github.com/aws/aws-dynamodb-encryption-java.git" + +[[case]] +advisory = "GHSA-w736-hf9p-qqh3" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.15.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "7de5f5a5929271ab25bce685089eb7ec564dac4b" +cwe = "CWE-862" +family = "access_control" +function = "clear" +function_lines = [[98, 118]] +id = "aws-aws-dynamodb-encryption-java-dc048ae6130b9000" +language = "java" +method = "fix_site" +parent = "14c6a95bf91b3b301c1b4f621abb2c97f155bd09" +path = "sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/internal/LRUCache.java" +post_fix = " public void clear() {\n map.clear();\n }\n" +pre_fix = " public void clear() {\n // The more complicated logic is to ensure that the listener is\n // actually called for all entries.\n if (listener != null) {\n List> removedEntries = new ArrayList>();\n synchronized (map) {\n Iterator> it = map.entrySet().iterator();\n while(it.hasNext()) {\n removedEntries.add(it.next());\n it.remove();\n }\n }\n for (Entry entry : removedEntries) {\n listener.onRemoval(entry);\n }\n } else {\n map.clear();\n }\n }\n\n @Override" +repo = "aws/aws-dynamodb-encryption-java" +url = "https://github.com/aws/aws-dynamodb-encryption-java.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "_get_most_recent_version" +function_lines = [[230, 272]] +id = "aws-aws-dynamodb-encryption-python-24b46b781636d2ae" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "src/dynamodb_encryption_sdk/material_providers/most_recent.py" +post_fix = " def _get_most_recent_version(self, ttl_action):\n # type: (bool) -> CryptographicMaterialsProvider\n \"\"\"Get the most recent version of the provider.\n\n If allowing local and we cannot obtain the lock, just return the most recent local\n version. Otherwise, wait for the lock and ask the provider store for the most recent\n version of the provider.\n\n :param TtlActions ttl_action: The ttl action to take for this version\n :returns: version and corresponding cryptographic materials provider\n :rtype: CryptographicMaterialsProvider\n \"\"\"\n blocking_wait = bool(ttl_action is TtlActions.EXPIRED)\n acquired = self._lock.acquire(blocking_wait)\n\n if not acquired:\n # We failed to acquire the lock.\n # If blocking, we will never reach this point.\n # If not blocking, we want whatever the latest local version is.\n _LOGGER.debug(\"Failed to acquire lock. Returning the last cached version.\")\n version = self._version\n _, provider = self._cache.get(version)\n return provider\n\n try:\n # If the entry was expired then we blocked waiting for the lock, so it's possible some other thread already\n # queried the provider store and re-populated the cache. If so, we don't want to re-query the provider\n # store, so check if the entry is back in the cache first\n if ttl_action is TtlActions.EXPIRED:\n try:\n _, provider = self._cache.get(self._version)\n return provider\n except KeyError:\n pass\n\n max_version = self._get_max_version()\n try:\n _, provider = self._cache.get(max_version)\n except KeyError:\n provider = self._get_provider(max_version)\n received_version = self._provider_store.version_from_material_description(\n provider._material_description # pylint: disable=protected-access\n )\n\n _LOGGER.debug(\"Caching materials provider version %d\", received_version)\n self._version = received_version # pylint: disable=attribute-defined-outside-init\n self._last_updated = time.time() # pylint: disable=attribute-defined-outside-init\n self._cache.put(received_version, (self._last_updated, provider))\n finally:\n self._lock.release()\n\n _LOGGER.debug(\"New latest version is %d\", self._version)\n\n return provider\n" +pre_fix = " def _get_most_recent_version(self, allow_local):\n # type: (bool) -> CryptographicMaterialsProvider\n \"\"\"Get the most recent version of the provider.\n\n If allowing local and we cannot obtain the lock, just return the most recent local\n version. Otherwise, wait for the lock and ask the provider store for the most recent\n version of the provider.\n\n :param bool allow_local: Should we allow returning the local version if we cannot obtain the lock?\n :returns: version and corresponding cryptographic materials provider\n :rtype: CryptographicMaterialsProvider\n \"\"\"\n acquired = self._lock.acquire(not allow_local)\n\n if not acquired:\n # We failed to acquire the lock.\n # If blocking, we will never reach this point.\n # If not blocking, we want whatever the latest local version is.\n _LOGGER.debug(\"Failed to acquire lock. Returning the last cached version.\")\n version = self._version\n return self._cache.get(version)\n\n try:\n max_version = self._get_max_version()\n try:\n provider = self._cache.get(max_version)\n except KeyError:\n provider = self._get_provider(max_version)\n received_version = self._provider_store.version_from_material_description(\n provider._material_description # pylint: disable=protected-access\n )\n\n _LOGGER.debug(\"Caching materials provider version %d\", received_version)\n self._version = received_version # pylint: disable=attribute-defined-outside-init\n self._last_updated = time.time() # pylint: disable=attribute-defined-outside-init\n self._cache.put(received_version, provider)\n finally:\n self._lock.release()\n\n _LOGGER.debug(\"New latest version is %d\", self._version)\n\n return provider\n" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "create_table" +function_lines = [[99, 125]] +id = "aws-aws-dynamodb-encryption-python-61dcd0a9861e08a9" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "src/dynamodb_encryption_sdk/material_providers/store/meta.py" +post_fix = " def create_table(cls, client, table_name, read_units, write_units):\n # type: (botocore.client.BaseClient, Text, int, int) -> None\n \"\"\"Create the table for this MetaStore.\n\n :param table: Pre-configured boto3 DynamoDB client object\n :type table: boto3.resources.base.BaseClient\n :param str table_name: Name of table to create\n :param int read_units: Read capacity units to provision\n :param int write_units: Write capacity units to provision\n \"\"\"\n _LOGGER.debug(\"Creating MetaStore table\")\n try:\n client.create_table(\n TableName=table_name,\n AttributeDefinitions=[\n {\"AttributeName\": MetaStoreAttributeNames.PARTITION.value, \"AttributeType\": \"S\"},\n {\"AttributeName\": MetaStoreAttributeNames.SORT.value, \"AttributeType\": \"N\"},\n ],\n KeySchema=[\n {\"AttributeName\": MetaStoreAttributeNames.PARTITION.value, \"KeyType\": \"HASH\"},\n {\"AttributeName\": MetaStoreAttributeNames.SORT.value, \"KeyType\": \"RANGE\"},\n ],\n ProvisionedThroughput={\"ReadCapacityUnits\": read_units, \"WriteCapacityUnits\": write_units},\n )\n except botocore.exceptions.ClientError as exc:\n raise Exception(\"Could not create table\", exc)\n" +pre_fix = " def create_table(cls, client, table_name, read_units, write_units):\n # type: (botocore.client.BaseClient, Text, int, int) -> None\n \"\"\"Create the table for this MetaStore.\n\n :param table: Pre-configured boto3 DynamoDB client object\n :type table: boto3.resources.base.BaseClient\n :param str table_name: Name of table to create\n :param int read_units: Read capacity units to provision\n :param int write_units: Write capacity units to provision\n \"\"\"\n _LOGGER.debug(\"Creating MetaStore table\")\n try:\n client.create_table(\n TableName=table_name,\n AttributeDefinitions=[\n {\"AttributeName\": MetaStoreAttributeNames.PARTITION.value, \"AttributeType\": \"S\"},\n {\"AttributeName\": MetaStoreAttributeNames.SORT.value, \"AttributeType\": \"N\"},\n ],\n KeySchema=[\n {\"AttributeName\": MetaStoreAttributeNames.PARTITION.value, \"KeyType\": \"HASH\"},\n {\"AttributeName\": MetaStoreAttributeNames.SORT.value, \"KeyType\": \"RANGE\"},\n ],\n ProvisionedThroughput={\"ReadCapacityUnits\": read_units, \"WriteCapacityUnits\": write_units},\n )\n except botocore.exceptions.ClientError:\n raise Exception(\"Could not create table\")\n" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "decryption_materials" +function_lines = [[158, 180]] +id = "aws-aws-dynamodb-encryption-python-73fd155703fd3f7f" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "src/dynamodb_encryption_sdk/material_providers/most_recent.py" +post_fix = " def decryption_materials(self, encryption_context):\n # type: (EncryptionContext) -> CryptographicMaterials\n \"\"\"Return decryption materials.\n\n :param EncryptionContext encryption_context: Encryption context for request\n :raises AttributeError: if no decryption materials are available\n \"\"\"\n version = self._provider_store.version_from_material_description(encryption_context.material_description)\n try:\n _LOGGER.debug(\"Looking in cache for decryption materials provider version %d\", version)\n _, provider = self._cache.get(version)\n except KeyError:\n _LOGGER.debug(\"Decryption materials provider not found in cache\")\n try:\n provider = self._provider_store.provider(self._material_name, version)\n self._cache.put(version, (time.time(), provider))\n except InvalidVersionError:\n _LOGGER.exception(\"Unable to get decryption materials from provider store.\")\n raise AttributeError(\"No decryption materials available\")\n\n return provider.decryption_materials(encryption_context)\n" +pre_fix = " def decryption_materials(self, encryption_context):\n # type: (EncryptionContext) -> CryptographicMaterials\n \"\"\"Return decryption materials.\n\n :param EncryptionContext encryption_context: Encryption context for request\n :raises AttributeError: if no decryption materials are available\n \"\"\"\n version = self._provider_store.version_from_material_description(encryption_context.material_description)\n try:\n _LOGGER.debug(\"Looking in cache for decryption materials provider version %d\", version)\n provider = self._cache.get(version)\n except KeyError:\n _LOGGER.debug(\"Decryption materials provider not found in cache\")\n try:\n provider = self._provider_store.provider(self._material_name, version)\n except InvalidVersionError:\n _LOGGER.exception(\"Unable to get decryption materials from provider store.\")\n raise AttributeError(\"No decryption materials available\")\n\n self._cache.put(version, provider)\n\n return provider.decryption_materials(encryption_context)\n" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "encryption_materials" +function_lines = [[273, 303]] +id = "aws-aws-dynamodb-encryption-python-9647ae75335f0a25" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "src/dynamodb_encryption_sdk/material_providers/most_recent.py" +post_fix = " def encryption_materials(self, encryption_context):\n # type: (EncryptionContext) -> CryptographicMaterials\n \"\"\"Return encryption materials.\n\n :param EncryptionContext encryption_context: Encryption context for request\n :raises AttributeError: if no encryption materials are available\n \"\"\"\n ttl_action = self._ttl_action(self._version, _ENCRYPT_ACTION)\n\n _LOGGER.debug('TTL Action \"%s\" when getting encryption materials', ttl_action.name)\n\n provider = None\n\n if ttl_action is TtlActions.EXPIRED:\n self._cache.evict(self._version)\n\n if ttl_action is TtlActions.LIVE:\n try:\n _LOGGER.debug(\"Looking in cache for encryption materials provider version %d\", self._version)\n _, provider = self._cache.get(self._version)\n except KeyError:\n _LOGGER.debug(\"Encryption materials provider not found in cache\")\n ttl_action = TtlActions.EXPIRED\n\n if provider is None:\n _LOGGER.debug(\"Getting most recent materials provider version\")\n provider = self._get_most_recent_version(ttl_action)\n\n return provider.encryption_materials(encryption_context)\n" +pre_fix = " def encryption_materials(self, encryption_context):\n # type: (EncryptionContext) -> CryptographicMaterials\n \"\"\"Return encryption materials.\n\n :param EncryptionContext encryption_context: Encryption context for request\n :raises AttributeError: if no encryption materials are available\n \"\"\"\n ttl_action = self._ttl_action()\n\n _LOGGER.debug('TTL Action \"%s\" when getting encryption materials', ttl_action.name)\n\n provider = None\n\n if ttl_action is TtlActions.LIVE:\n try:\n _LOGGER.debug(\"Looking in cache for encryption materials provider version %d\", self._version)\n provider = self._cache.get(self._version)\n except KeyError:\n _LOGGER.debug(\"Encryption materials provider not found in cache\")\n ttl_action = TtlActions.EXPIRED\n\n if provider is None:\n # Just get the latest local version if we cannot acquire the lock.\n # Otherwise, block until we can acquire the lock.\n allow_local = bool(ttl_action is TtlActions.GRACE_PERIOD)\n\n _LOGGER.debug(\"Getting most recent materials provider version\")\n provider = self._get_most_recent_version(allow_local)\n\n return provider.encryption_materials(encryption_context)\n" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "_ttl_action" +function_lines = [[181, 202]] +id = "aws-aws-dynamodb-encryption-python-b3f52b37033a02d3" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "src/dynamodb_encryption_sdk/material_providers/most_recent.py" +post_fix = " def _ttl_action(self, version, action):\n # type: (str) -> TtlActions\n \"\"\"Determine the correct action to take based on the local resources and TTL.\n\n :param action: The action being taken (encrypt or decrypt)\n\n :returns: decision\n :rtype: TtlActions\n \"\"\"\n try:\n if action == _ENCRYPT_ACTION:\n # On encrypt, always check the class-level variable indicating when we last checked for updates.\n # The cache timestamps will be updated by calls to decrypt, so we don't want frequent decrypts to\n # prevent us from re-checking for a newer encryption version\n if self._last_updated is None:\n return TtlActions.EXPIRED\n timestamp = self._last_updated\n else:\n timestamp, _ = self._cache.get(version)\n time_since_updated = time.time() - timestamp\n\n if time_since_updated < self._version_ttl:\n return TtlActions.LIVE\n\n if time_since_updated < self._version_ttl + self._grace_period:\n return TtlActions.GRACE_PERIOD\n\n _LOGGER.debug(\"TTL Expired because known version has expired\")\n return TtlActions.EXPIRED\n except KeyError:\n _LOGGER.debug(\"TTL Expired because the requested version doesn't exist in the cache\")\n return TtlActions.EXPIRED\n" +pre_fix = " def _ttl_action(self):\n # type: () -> TtlActions\n \"\"\"Determine the correct action to take based on the local resources and TTL.\n\n :returns: decision\n :rtype: TtlActions\n \"\"\"\n if self._version is None:\n _LOGGER.debug(\"TTL Expired because no version is known\")\n return TtlActions.EXPIRED\n\n time_since_updated = time.time() - self._last_updated\n\n if time_since_updated < self._version_ttl:\n return TtlActions.LIVE\n\n if time_since_updated < self._version_ttl + _GRACE_PERIOD:\n return TtlActions.GRACE_PERIOD\n\n _LOGGER.debug(\"TTL Expired because known version has expired\")\n return TtlActions.EXPIRED\n" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "get" +function_lines = [[100, 111]] +id = "aws-aws-dynamodb-encryption-python-bf080d1693c13e38" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "src/dynamodb_encryption_sdk/material_providers/most_recent.py" +post_fix = " def get(self, name):\n # type: (Any) -> Any\n \"\"\"Get a value from the cache.\n\n :param name: Object to identify the value in the cache\n :returns: Value from cache\n \"\"\"\n with self._cache_lock:\n value = self._cache.pop(name)\n # Re-insert the item to bump it to the front of the LRU cache\n self.put(name, value)\n return value\n" +pre_fix = " def get(self, name):\n # type: (Any) -> Any\n \"\"\"Get a value from the cache.\n\n :param name: Object to identify the value in the cache\n :returns: Value from cache\n \"\"\"\n with self._cache_lock:\n value = self._cache.pop(name)\n self.put(name, value) # bump to the from of the LRU\n return value\n" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-4ph2-8337-hm62" +advisory_text = "Key Caching behavior in the DynamoDB Encryption Client.\n\n### Impact\nThis advisory concerns users of MostRecentProvider in the DynamoDB Encryption Client with a key provider like AWS Key Management Service that allows for permissions on keys to be modified.\n\nWhen key usage permissions were changed at the key provider, time-based key reauthorization logic in MostRecentProvider did not reauthorize the use of the key. This created the potential for keys to be used in the DynamoDB Encryption Client after permissions to do so were revoked at the key provider.\n\n### Patches\nFixed as of 1.3.0. We recommend users to modify their code and adopt `CachingMostRecentProvider`.\n\n\n### Workarounds\nUsers who cannot upgrade to use the `CachingMostRecentProvider` can call `clear()` on the cache to manually flush all of its contents. Next use of the key will force a re-validation to occur with the key provider." +commit = "90606ec9af7c2b5cb338d64639a62ee867d38d6b" +cwe = "CWE-862" +family = "access_control" +function = "encrypt_item" +function_lines = [[25, 83]] +id = "aws-aws-dynamodb-encryption-python-d713ce65ca1d1e54" +language = "python" +method = "fix_site" +parent = "f133fc2dc4cfa763829faa5be7ea8f23140a5f1d" +path = "examples/src/most_recent_provider_encrypted_table.py" +post_fix = "def encrypt_item(table_name, aws_cmk_id, meta_table_name, material_name):\n \"\"\"Demonstrate use of EncryptedTable to transparently encrypt an item.\"\"\"\n index_key = {\"partition_attribute\": \"is this\", \"sort_attribute\": 55}\n plaintext_item = {\n \"example\": \"data\",\n \"some numbers\": 99,\n \"and some binary\": Binary(b\"\\x00\\x01\\x02\"),\n \"leave me\": \"alone\", # We want to ignore this attribute\n }\n # Collect all of the attributes that will be encrypted (used later).\n encrypted_attributes = set(plaintext_item.keys())\n encrypted_attributes.remove(\"leave me\")\n # Collect all of the attributes that will not be encrypted (used later).\n unencrypted_attributes = set(index_key.keys())\n unencrypted_attributes.add(\"leave me\")\n # Add the index pairs to the item.\n plaintext_item.update(index_key)\n\n # Create a normal table resource for the meta store.\n meta_table = boto3.resource(\"dynamodb\").Table(meta_table_name) # generated code confuse pylint: disable=no-member\n # Create a crypto materials provider for the meta store using the specified AWS KMS key.\n aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)\n # Create a meta store using the AWS KMS crypto materials provider.\n meta_store = MetaStore(table=meta_table, materials_provider=aws_kms_cmp)\n # Create a most recent provider using the meta store.\n most_recent_cmp = CachingMostRecentProvider(\n provider_store=meta_store,\n material_name=material_name,\n version_ttl=600.0, # Check for a new material version every five minutes.\n )\n # Create a normal table resource.\n table = boto3.resource(\"dynamodb\").Table(table_name) # generated code confuse pylint: disable=no-member\n # Create attribute actions that tells the encrypted table to encrypt all attributes except one.\n actions = AttributeActions(\n default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={\"leave me\": CryptoAction.DO_NOTHING}\n )\n # Use these objects to create an encrypted table resource.\n encrypted_table = EncryptedTable(table=table, materials_provider=most_recent_cmp, attribute_actions=actions)\n\n # Put the item to the table, using the encrypted table resource to transparently encrypt it.\n encrypted_table.put_item(Item=plaintext_item)\n\n # Get the encrypted item using the standard table resource.\n encrypted_item = table.get_item(Key=index_key)[\"Item\"]\n\n # Get the item using the encrypted table resource, transparently decyrpting it.\n decrypted_item = encrypted_table.get_item(Key=index_key)[\"Item\"]\n\n # Verify that all of the attributes are different in the encrypted item\n for name in encrypted_attributes:\n assert encrypted_item[name] != plaintext_item[name]\n assert decrypted_item[name] == plaintext_item[name]\n\n # Verify that all of the attributes that should not be encrypted were not.\n for name in unencrypted_attributes:\n assert decrypted_item[name] == encrypted_item[name] == plaintext_item[name]\n\n # Clean up the item\n encrypted_table.delete_item(Key=index_key)" +pre_fix = "def encrypt_item(table_name, aws_cmk_id, meta_table_name, material_name):\n \"\"\"Demonstrate use of EncryptedTable to transparently encrypt an item.\"\"\"\n index_key = {\"partition_attribute\": \"is this\", \"sort_attribute\": 55}\n plaintext_item = {\n \"example\": \"data\",\n \"some numbers\": 99,\n \"and some binary\": Binary(b\"\\x00\\x01\\x02\"),\n \"leave me\": \"alone\", # We want to ignore this attribute\n }\n # Collect all of the attributes that will be encrypted (used later).\n encrypted_attributes = set(plaintext_item.keys())\n encrypted_attributes.remove(\"leave me\")\n # Collect all of the attributes that will not be encrypted (used later).\n unencrypted_attributes = set(index_key.keys())\n unencrypted_attributes.add(\"leave me\")\n # Add the index pairs to the item.\n plaintext_item.update(index_key)\n\n # Create a normal table resource for the meta store.\n meta_table = boto3.resource(\"dynamodb\").Table(meta_table_name) # generated code confuse pylint: disable=no-member\n # Create a crypto materials provider for the meta store using the specified AWS KMS key.\n aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)\n # Create a meta store using the AWS KMS crypto materials provider.\n meta_store = MetaStore(table=meta_table, materials_provider=aws_kms_cmp)\n # Create a most recent provider using the meta store.\n most_recent_cmp = MostRecentProvider(\n provider_store=meta_store,\n material_name=material_name,\n version_ttl=600.0, # Check for a new material version every five minutes.\n )\n # Create a normal table resource.\n table = boto3.resource(\"dynamodb\").Table(table_name) # generated code confuse pylint: disable=no-member\n # Create attribute actions that tells the encrypted table to encrypt all attributes except one.\n actions = AttributeActions(\n default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={\"leave me\": CryptoAction.DO_NOTHING}\n )\n # Use these objects to create an encrypted table resource.\n encrypted_table = EncryptedTable(table=table, materials_provider=most_recent_cmp, attribute_actions=actions)\n\n # Put the item to the table, using the encrypted table resource to transparently encrypt it.\n encrypted_table.put_item(Item=plaintext_item)\n\n # Get the encrypted item using the standard table resource.\n encrypted_item = table.get_item(Key=index_key)[\"Item\"]\n\n # Get the item using the encrypted table resource, transparently decyrpting it.\n decrypted_item = encrypted_table.get_item(Key=index_key)[\"Item\"]\n\n # Verify that all of the attributes are different in the encrypted item\n for name in encrypted_attributes:\n assert encrypted_item[name] != plaintext_item[name]\n assert decrypted_item[name] == plaintext_item[name]\n\n # Verify that all of the attributes that should not be encrypted were not.\n for name in unencrypted_attributes:\n assert decrypted_item[name] == encrypted_item[name] == plaintext_item[name]\n\n # Clean up the item\n encrypted_table.delete_item(Key=index_key)" +repo = "aws/aws-dynamodb-encryption-python" +url = "https://github.com/aws/aws-dynamodb-encryption-python.git" + +[[case]] +advisory = "GHSA-qmv4-jgp7-mf68" +advisory_text = "Sails before 0.12.7 vulnerable to Broken CORS\n\nAffected versions of `sails` have an issue with the CORS configuration where the value of the origin header is reflected as the value for the `Access-Control-Allow-Origin` header. This may allow an attacker to make AJAX requests to vulnerable hosts through cross-site scripting or a malicious HTML Document, effectively bypassing the Same Origin Policy. \n\n## Mitigating Factors\n\nThis is only an issue when `allRoutes` is set to `true` and `origin` is set to `*` or left commented out in the sails CORS config file. \n\nThe problem can be compounded when the cors `credentials` setting is not provided, because at that point authenticated cross domain requests are possible.\n\n\n## Recommendation\n\nUpdate to version 0.12.7 or later.\n\nAs this vulnerability is primarily a user error, the patch for the vulnerability will simply cause the application to write an error message to the console when a vulnerable configuration is used in a production environment.\n\nWriting a proper CORS configuration is still the responsibility of the user, so it is necessary to check for the error message after installing the patch. Be sure you are not using `allRoutes: true` with `origin:'*'`, and that you uncomment `origin` and set it to a reasonable value. Ensure that if `origin` is set to `*` that you truly mean for all other websites to be able to make cross-domain requests to your API.\n\nLikewise, ensure `credentials` is uncommented out and set to the appropriate value. Make sure to explicitly set which origins may request resources via CORS." +commit = "0057123a0321be6758845abbeb4290bf418ce542" +cwe = "CWE-284" +family = "access_control" +function = "function" +function_lines = [[1, 151]] +id = "balderdashy-sails-b89551ad8023e1de" +language = "javascript" +method = "fix_site" +parent = "8d642f1ab3d46491cf7b73af1ec54941ff0eb84b" +path = "lib/hooks/cors/index.js" +post_fix = "module.exports = function(sails) {\n\n /**\n * Module dependencies.\n */\n\n var _ = require('lodash');\n var clearHeaders = require('./clear-headers');\n var prepareSendHeaders = require('./to-prepare-send-headers')(sails);\n\n\n /**\n * Expose hook definition\n */\n\n return {\n\n // These constants are for private use within the hook.\n SECURITY_LEVEL_NORMAL: 0,\n SECURITY_LEVEL_HIGH: 1,\n SECURITY_LEVEL_VERYHIGH: 2,\n\n\n /**\n * Implicit defaults\n * @type {Dictionary}\n */\n defaults: {\n cors: {\n origin: '*',\n allRoutes: false,\n credentials: true,\n methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD',\n headers: 'content-type',\n exposeHeaders: '',\n securityLevel: 0,\n }\n },\n\n\n /**\n * When this hook loads...\n * @param {Function} cb\n */\n initialize: function(cb) {\n\n // Declare an array to hold info about unsafely-configured routes.\n var unsafeRoutes = [];\n\n // Once it's time to bind shadow routes, get to bindin'.\n sails.on('router:before', function () {\n // (TODO: consider changing this ^^ to `sails.after()` for consistency)\n\n // If we're setting CORS on all routes by default, set up a universal route for it here.\n // CORS can still be turned off for specific routes by setting `cors:false`\n if (sails.config.cors.allRoutes === true) {\n sails.router.bind('/*', prepareSendHeaders(), 'all', {_middlewareType: 'CORS HOOK: sendHeaders'});\n }\n // Otherwise clear all the headers by default\n else {\n sails.router.bind('/*', clearHeaders, 'all', {_middlewareType: 'CORS HOOK: clearHeaders'});\n }\n\n var optionsRouteConfigs = {};\n\n // Loop through all configured routes, looking for CORS options\n _.each(sails.config.routes, function(config, route) {\n\n var routeInfo = sails.util.detectVerb(route);\n var path = routeInfo.original.toLowerCase();\n var verb = routeInfo.verb.toLowerCase();\n\n if (!_.isUndefined(config.cors)) {\n\n optionsRouteConfigs[path] = optionsRouteConfigs[path] || {'default': sails.config.cors};\n\n // If cors is set to `true`, and we're not doing all routes by default, set\n // the CORS headers for this route using the default origin\n if (config.cors === true) {\n // Use the default CORS config for this path on an OPTIONS request\n optionsRouteConfigs[path][verb || 'default'] = sails.config.cors;\n if (!sails.config.cors.allRoutes) {\n sails.router.bind(route, prepareSendHeaders(), null);\n }\n }\n\n // If cors is set to `false`, clear the CORS headers for this route\n else if (config.cors === false) {\n // Clear headers on an OPTIONS request for this path\n optionsRouteConfigs[path][verb || 'default'] = 'clear';\n sails.router.bind(route, clearHeaders, null, {_middlewareType: 'CORS HOOK: clearHeaders'});\n return;\n }\n\n\n // Else if cors is set to a string, use that has the origin\n else if (typeof config.cors === 'string') {\n optionsRouteConfigs[path][verb || 'default'] = _.extend({origin: config.cors},{methods: verb});\n sails.router.bind(route, prepareSendHeaders({origin:config.cors}), null);\n }\n\n // Else if cors is an object, use that as the config\n else if (_.isPlainObject(config.cors)) {\n // If the route has a verb, it shouldn't have a `methods` CORS setting\n if (routeInfo.verb && config.cors.methods) {\n sails.log.warn('Ignoring `methods` CORS setting for route '+route+' because it has a verb specified.');\n config.cors.methods = verb;\n }\n optionsRouteConfigs[path][verb || 'default'] = config.cors;\n sails.router.bind(route, prepareSendHeaders(config.cors), null);\n }\n\n // Otherwise throw a warning\n else {\n sails.log.warn('Invalid CORS settings for route '+route);\n }\n\n // If the global CORS defaults are not overly permissive, check this individual route's settings.\n if (sails.config.cors.allRoutes === false || sails.config.cors.origin !== '*' || sails.config.cors.credentials === false) {\n var routeCorsConfig = _.defaults(optionsRouteConfigs[path][verb || 'default'], sails.config.cors);\n // If they are too permissive, add the route to a list of unsafe routes to warn the user about\n // when running in the production environment.\n if (routeCorsConfig.origin === '*' && routeCorsConfig.credentials === true) {\n unsafeRoutes.push((verb ? (verb + ' ') : '') + path);\n }\n }\n\n }\n\n });\n\n // Log a warning if your default CORS settings are super permissive in the production environment.\n if (sails.config.environment === 'production') {\n // If the global CORS defaults are permissive, log a warning about that.\n if (\n sails.config.cors.allRoutes === true &&\n sails.config.cors.origin === '*' &&\n sails.config.cors.credentials === true\n ) {\n sails.log.error('\\n' +\n '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n' +\n 'WARNING: You currently have your default CORS settings configured to allow\\n' +\n 'all requests from all origins, with credentials. This may leave your app\\n' +\n 'open to attack by third-party sites! Consider making your `origins` setting\\n' +\n 'more restrictive or setting `credentials` to false, or else make certain that\\n' +\n 'none of your routes perform sensitive actions or reveal secure information.\\n' +\n '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n');\n }\n // Otherwise log a warning mentioning the particular routes that are too permissive.\n else if (unsafeRoutes.length) {\n sails.log.error('\\n' +\n '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n' +\n 'WARNING: You currently have CORS settings on the following routes configured\\n' +\n 'to allow all requests from all origins, with credentials:\\n\\n' + unsafeRoutes.join('\\n') + '\\n\\n' +\n 'This may leave these routes open to attack by third-party sites! Consider\\n'+\n 'making the `origins` settings more restrictive or setting `credentials` to\\n' +\n 'false, or else make certain that none of these routes perform sensitive\\n' +\n 'actions or reveal secure information.\\n' +\n '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n'\n );\n }\n }\n\n\n\n\n _.each(optionsRouteConfigs, function(config, path) {\n sails.router.bind('options '+path, prepareSendHeaders(config, true), null, {_middlewareType: 'CORS HOOK: preflight'});\n });\n\n // IF SECURITY_LEVEL > 'normal'--don't process requests from disallowed origins.\n //\n // We can't just rely on the browser implementing 'access-control-allow-origin' correctly;\n // we need to make sure that if a request is made from an origin that isn't whitelisted,\n // that we don't end up processing that request.\n if (sails.config.cors.securityLevel > sails.hooks.cors.SECURITY_LEVEL_NORMAL) {\n sails.router.bind('/*', function(req, res, next) {\n\n // If it's a cross-origin request, and the access-control-allow-origin header doesn't match\n // the origin header, then we don't approve of this origin and shouldn't continue\n // with this request.\n if (!sails.util.isSameOrigin(req, sails.config.cors.securityLevel == sails.hooks.cors.SECURITY_LEVEL_VERYHIGH) && res.get('Access-Control-Allow-Origin') != req.headers.origin) {\n return res.forbidden();\n }\n return next();\n }, null, {_middlewareType: 'CORS HOOK: catchall'});\n }\n\n });\n\n\n // Continue loading this Sails app.\n return cb();\n\n }//\n\n };\n\n};" +pre_fix = "module.exports = function(sails) {\n\n /**\n * Module dependencies.\n */\n\n var _ = require('lodash');\n var clearHeaders = require('./clear-headers');\n var prepareSendHeaders = require('./to-prepare-send-headers')(sails);\n\n\n /**\n * Expose hook definition\n */\n\n return {\n\n // These constants are for private use within the hook.\n SECURITY_LEVEL_NORMAL: 0,\n SECURITY_LEVEL_HIGH: 1,\n SECURITY_LEVEL_VERYHIGH: 2,\n\n\n /**\n * Implicit defaults\n * @type {Dictionary}\n */\n defaults: {\n cors: {\n origin: '*',\n allRoutes: false,\n credentials: true,\n methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD',\n headers: 'content-type',\n exposeHeaders: '',\n securityLevel: 0,\n }\n },\n\n\n /**\n * When this hook loads...\n * @param {Function} cb\n */\n initialize: function(cb) {\n\n // Once it's time to bind shadow routes, get to bindin'.\n sails.on('router:before', function () {\n // (TODO: consider changing this ^^ to `sails.after()` for consistency)\n\n // If we're setting CORS on all routes by default, set up a universal route for it here.\n // CORS can still be turned off for specific routes by setting `cors:false`\n if (sails.config.cors.allRoutes === true) {\n sails.router.bind('/*', prepareSendHeaders(), 'all', {_middlewareType: 'CORS HOOK: sendHeaders'});\n }\n // Otherwise clear all the headers by default\n else {\n sails.router.bind('/*', clearHeaders, 'all', {_middlewareType: 'CORS HOOK: clearHeaders'});\n }\n\n var optionsRouteConfigs = {};\n\n // Loop through all configured routes, looking for CORS options\n _.each(sails.config.routes, function(config, route) {\n\n var routeInfo = sails.util.detectVerb(route);\n var path = routeInfo.original.toLowerCase();\n var verb = routeInfo.verb.toLowerCase();\n\n if (!_.isUndefined(config.cors)) {\n\n optionsRouteConfigs[path] = optionsRouteConfigs[path] || {'default': sails.config.cors};\n\n // If cors is set to `true`, and we're not doing all routes by default, set\n // the CORS headers for this route using the default origin\n if (config.cors === true) {\n // Use the default CORS config for this path on an OPTIONS request\n optionsRouteConfigs[path][verb || 'default'] = sails.config.cors;\n if (!sails.config.cors.allRoutes) {\n sails.router.bind(route, prepareSendHeaders(), null);\n }\n }\n\n // If cors is set to `false`, clear the CORS headers for this route\n else if (config.cors === false) {\n // Clear headers on an OPTIONS request for this path\n optionsRouteConfigs[path][verb || 'default'] = 'clear';\n sails.router.bind(route, clearHeaders, null, {_middlewareType: 'CORS HOOK: clearHeaders'});\n return;\n }\n\n\n // Else if cors is set to a string, use that has the origin\n else if (typeof config.cors === 'string') {\n optionsRouteConfigs[path][verb || 'default'] = _.extend({origin: config.cors},{methods: verb});\n sails.router.bind(route, prepareSendHeaders({origin:config.cors}), null);\n }\n\n // Else if cors is an object, use that as the config\n else if (_.isPlainObject(config.cors)) {\n // If the route has a verb, it shouldn't have a `methods` CORS setting\n if (routeInfo.verb && config.cors.methods) {\n sails.log.warn('Ignoring `methods` CORS setting for route '+route+' because it has a verb specified.');\n config.cors.methods = verb;\n }\n optionsRouteConfigs[path][verb || 'default'] = config.cors;\n sails.router.bind(route, prepareSendHeaders(config.cors), null);\n }\n\n // Otherwise throw a warning\n else {\n sails.log.warn('Invalid CORS settings for route '+route);\n }\n\n }\n\n });\n\n _.each(optionsRouteConfigs, function(config, path) {\n sails.router.bind('options '+path, prepareSendHeaders(config, true), null, {_middlewareType: 'CORS HOOK: preflight'});\n });\n\n // IF SECURITY_LEVEL > 'normal'--don't process requests from disallowed origins.\n //\n // We can't just rely on the browser implementing 'access-control-allow-origin' correctly;\n // we need to make sure that if a request is made from an origin that isn't whitelisted,\n // that we don't end up processing that request.\n if (sails.config.cors.securityLevel > sails.hooks.cors.SECURITY_LEVEL_NORMAL) {\n sails.router.bind('/*', function(req, res, next) {\n\n // If it's a cross-origin request, and the access-control-allow-origin header doesn't match\n // the origin header, then we don't approve of this origin and shouldn't continue\n // with this request.\n if (!sails.util.isSameOrigin(req, sails.config.cors.securityLevel == sails.hooks.cors.SECURITY_LEVEL_VERYHIGH) && res.get('Access-Control-Allow-Origin') != req.headers.origin) {\n return res.forbidden();\n }\n return next();\n }, null, {_middlewareType: 'CORS HOOK: catchall'});\n }\n\n });\n\n\n // Continue loading this Sails app.\n return cb();\n\n }//\n\n };\n\n};" +repo = "balderdashy/sails" +url = "https://github.com/balderdashy/sails.git" + +[[case]] +advisory = "GHSA-52gq-7j6c-xw6x" +advisory_text = "Missing Authentication for Critical Function in Apache Cassandra\n\nThe default configuration in Apache Cassandra 3.8 through 3.11.1 binds an unauthenticated JMX/RMI interface to all network interfaces, which allows remote attackers to execute arbitrary Java code via an RMI request. This issue is a regression of CVE-2015-0225. The regression was introduced in https://issues.apache.org/jira/browse/CASSANDRA-12109. The fix for the regression is implemented in https://issues.apache.org/jira/browse/CASSANDRA-14173. This fix is contained in the 3.11.2 release of Apache Cassandra." +commit = "28ee665b3c0c9238b61a871064f024d54cddcc79" +cwe = "CWE-306" +family = "access_control" +function = "createJMXServer" +function_lines = [[62, 112]] +id = "beobal-cassandra-695047212ddf8d34" +language = "java" +method = "fix_site" +parent = "6b00767427706124e016e4f471c2266899387163" +path = "src/java/org/apache/cassandra/utils/JMXServerUtils.java" +post_fix = " public static JMXConnectorServer createJMXServer(int port, boolean local)\n throws IOException\n {\n Map env = new HashMap<>();\n\n InetAddress serverAddress = null;\n if (local)\n {\n serverAddress = InetAddress.getLoopbackAddress();\n System.setProperty(\"java.rmi.server.hostname\", serverAddress.getHostAddress());\n }\n\n // Configure the RMI client & server socket factories, including SSL config.\n env.putAll(configureJmxSocketFactories(serverAddress, local));\n\n // configure the RMI registry to use the socket factories we just created\n Registry registry = LocateRegistry.createRegistry(port,\n (RMIClientSocketFactory) env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE),\n (RMIServerSocketFactory) env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE));\n\n // Configure authn, using a JMXAuthenticator which either wraps a set log LoginModules configured\n // via a JAAS configuration entry, or one which delegates to the standard file based authenticator.\n // Authn is disabled if com.sun.management.jmxremote.authenticate=false\n env.putAll(configureJmxAuthentication());\n\n // Configure authz - if a custom proxy class is specified an instance will be returned.\n // If not, but a location for the standard access file is set in system properties, the\n // return value is null, and an entry is added to the env map detailing that location\n // If neither method is specified, no access control is applied\n MBeanServerForwarder authzProxy = configureJmxAuthorization(env);\n\n // Mark the JMX server as a permanently exported object. This allows the JVM to exit with the\n // server running and also exempts it from the distributed GC scheduler which otherwise would\n // potentially attempt a full GC every `sun.rmi.dgc.server.gcInterval` millis (default is 3600000ms)\n // For more background see:\n // - CASSANDRA-2967\n // - https://www.jclarity.com/2015/01/27/rmi-system-gc-unplugged/\n // - https://bugs.openjdk.java.net/browse/JDK-6760712\n env.put(\"jmx.remote.x.daemon\", \"true\");\n\n // Set the port used to create subsequent connections to exported objects over RMI. This simplifies\n // configuration in firewalled environments, but it can't be used in conjuction with SSL sockets.\n // See: CASSANDRA-7087\n int rmiPort = Integer.getInteger(\"com.sun.management.jmxremote.rmi.port\", 0);\n\n // We create the underlying RMIJRMPServerImpl so that we can manually bind it to the registry,\n // rather then specifying a binding address in the JMXServiceURL and letting it be done automatically\n // when the server is started. The reason for this is that if the registry is configured with SSL\n // sockets, the JMXConnectorServer acts as its client during the binding which means it needs to\n // have a truststore configured which contains the registry's certificate. Manually binding removes\n // this problem.\n // See CASSANDRA-12109.\n RMIJRMPServerImpl server = new RMIJRMPServerImpl(rmiPort,\n (RMIClientSocketFactory) env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE),\n (RMIServerSocketFactory) env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE),\n env);\n JMXServiceURL serviceURL = new JMXServiceURL(\"rmi\", null, rmiPort);\n RMIConnectorServer jmxServer = new RMIConnectorServer(serviceURL, env, server, ManagementFactory.getPlatformMBeanServer());\n\n // If a custom authz proxy was created, attach it to the server now.\n if (authzProxy != null)\n jmxServer.setMBeanServerForwarder(authzProxy);\n jmxServer.start();\n\n registry.rebind(\"jmxrmi\", server);\n logJmxServiceUrl(serverAddress, port);\n return jmxServer;\n }\n\n private static Map configureJmxAuthentication()\n {\n Map env = new HashMap<>();\n if (!Boolean.getBoolean(\"com.sun.management.jmxremote.authenticate\"))\n return env;\n\n // If authentication is enabled, initialize the appropriate JMXAuthenticator\n // and stash it in the environment settings.\n // A JAAS configuration entry takes precedence. If one is supplied, use\n // Cassandra's own custom JMXAuthenticator implementation which delegates\n // auth to the LoginModules specified by the JAAS configuration entry.\n // If no JAAS entry is found, an instance of the JDK's own\n // JMXPluggableAuthenticator is created. In that case, the admin may have\n // set a location for the JMX password file which must be added to env\n // before creating the authenticator. If no password file has been\n // explicitly set, it's read from the default location\n // $JAVA_HOME/lib/management/jmxremote.password\n String configEntry = System.getProperty(\"cassandra.jmx.remote.login.config\");\n if (configEntry != null)\n {\n env.put(JMXConnectorServer.AUTHENTICATOR, new AuthenticationProxy(configEntry));\n }\n else\n {\n String passwordFile = System.getProperty(\"com.sun.management.jmxremote.password.file\");\n if (passwordFile != null)\n {\n // stash the password file location where JMXPluggableAuthenticator expects it\n env.put(\"jmx.remote.x.password.file\", passwordFile);\n }\n\n env.put(JMXConnectorServer.AUTHENTICATOR, new JMXPluggableAuthenticatorWrapper(env));\n }\n\n return env;\n }\n" +pre_fix = " public static JMXConnectorServer createJMXServer(int port, boolean local)\n throws IOException\n {\n Map env = new HashMap<>();\n\n InetAddress serverAddress = null;\n if (local)\n {\n serverAddress = InetAddress.getLoopbackAddress();\n System.setProperty(\"java.rmi.server.hostname\", serverAddress.getHostAddress());\n }\n\n // Configure the RMI client & server socket factories, including SSL config.\n env.putAll(configureJmxSocketFactories(serverAddress, local));\n\n\n // Configure authn, using a JMXAuthenticator which either wraps a set log LoginModules configured\n // via a JAAS configuration entry, or one which delegates to the standard file based authenticator.\n // Authn is disabled if com.sun.management.jmxremote.authenticate=false\n env.putAll(configureJmxAuthentication());\n\n // Configure authz - if a custom proxy class is specified an instance will be returned.\n // If not, but a location for the standard access file is set in system properties, the\n // return value is null, and an entry is added to the env map detailing that location\n // If neither method is specified, no access control is applied\n MBeanServerForwarder authzProxy = configureJmxAuthorization(env);\n\n // Make sure we use our custom exporter so a full GC doesn't get scheduled every\n // sun.rmi.dgc.server.gcInterval millis (default is 3600000ms/1 hour)\n env.put(RMIExporter.EXPORTER_ATTRIBUTE, new Exporter());\n\n\n int rmiPort = Integer.getInteger(\"com.sun.management.jmxremote.rmi.port\", 0);\n JMXConnectorServer jmxServer =\n JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL(\"rmi\", null, rmiPort),\n env,\n ManagementFactory.getPlatformMBeanServer());\n\n // If a custom authz proxy was created, attach it to the server now.\n if (authzProxy != null)\n jmxServer.setMBeanServerForwarder(authzProxy);\n\n jmxServer.start();\n\n // use a custom Registry to avoid having to interact with it internally using the remoting interface\n configureRMIRegistry(port, env);\n\n logJmxServiceUrl(serverAddress, port);\n return jmxServer;\n }\n" +repo = "beobal/cassandra" +url = "https://github.com/beobal/cassandra.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "doFilter" +function_lines = [[129, 159]] +id = "dromara-sa-token-1784eba75b914622" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java" +post_fix = "\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\t\t\n\t\ttry {\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(response.getContentType() == null) {\n\t\t\t\tresponse.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);\n\t\t\t}\n\t\t\tresponse.getWriter().print(result);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// 执行 \n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override" +pre_fix = "\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\t\t\n\t\ttry {\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(response.getContentType() == null) {\n\t\t\t\tresponse.setContentType(\"text/plain; charset=utf-8\"); \n\t\t\t}\n\t\t\tresponse.getWriter().print(result);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// 执行 \n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "getRequestPath" +function_lines = [[126, 134]] +id = "dromara-sa-token-4606223180a03c69" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java" +post_fix = "\tpublic String getRequestPath() {\n\t\treturn ApplicationInfo.cutPathPrefix(request.getRequestURI());\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */\n\t@Override" +pre_fix = "\tpublic String getRequestPath() {\n\t\treturn request.getServletPath();\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */\n\t@Override" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "getRequestPath" +function_lines = [[114, 121]] +id = "dromara-sa-token-52d82e15725937c7" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java" +post_fix = "\tpublic String getRequestPath() {\n\t\treturn ApplicationInfo.cutPathPrefix(request.getPath().toString());\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */" +pre_fix = "\tpublic String getRequestPath() {\n\t\treturn request.getURI().getPath();\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "filter" +function_lines = [[131, 183]] +id = "dromara-sa-token-761314754a33cca1" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java" +post_fix = "\tpublic Mono filter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\t\n\t\t// 写入WebFilterChain对象 \n\t\texchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);\n\t\t\n\t\t// ---------- 全局认证处理 \n\t\ttry {\n\t\t\t// 写入全局上下文 (同步) \n\t\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\t\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {\n\t\t\t\texchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);\n\t\t\t}\n\t\t\treturn exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));\n\t\t\t\n\t\t} finally {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t}\n\n\t\t// ---------- 执行\n\n\t\t// 写入全局上下文 (同步) \n\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\n\t\t// 执行 \n\t\treturn chain.filter(exchange).contextWrite(ctx -> {\n\t\t\t// 写入全局上下文 (异步) \n\t\t\tctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);\n\t\t\treturn ctx;\n\t\t}).doFinally(r -> {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t});\n\t}\n\t\n}" +pre_fix = "\tpublic Mono filter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\t\n\t\t// 写入WebFilterChain对象 \n\t\texchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);\n\t\t\n\t\t// ---------- 全局认证处理 \n\t\ttry {\n\t\t\t// 写入全局上下文 (同步) \n\t\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\t\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(exchange.getResponse().getHeaders().getFirst(\"Content-Type\") == null) {\n\t\t\t\texchange.getResponse().getHeaders().set(\"Content-Type\", \"text/plain; charset=utf-8\");\n\t\t\t}\n\t\t\treturn exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));\n\t\t\t\n\t\t} finally {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t}\n\n\t\t// ---------- 执行\n\n\t\t// 写入全局上下文 (同步) \n\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\n\t\t// 执行 \n\t\treturn chain.filter(exchange).contextWrite(ctx -> {\n\t\t\t// 写入全局上下文 (异步) \n\t\t\tctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);\n\t\t\treturn ctx;\n\t\t}).doFinally(r -> {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t});\n\t}\n\t\n}" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "getRequestPath" +function_lines = [[115, 122]] +id = "dromara-sa-token-7dfc28bc57def786" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java" +post_fix = "\tpublic String getRequestPath() {\n\t\treturn ApplicationInfo.cutPathPrefix(request.getPath().toString());\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */" +pre_fix = "\tpublic String getRequestPath() {\n\t\treturn request.getURI().getPath();\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "doFilter" +function_lines = [[130, 160]] +id = "dromara-sa-token-7fdb18d581095fae" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java" +post_fix = "\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\t\t\n\t\ttry {\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(response.getContentType() == null) {\n\t\t\t\tresponse.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);\n\t\t\t}\n\t\t\tresponse.getWriter().print(result);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// 执行 \n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override" +pre_fix = "\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n\t\t\n\t\ttry {\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(response.getContentType() == null) {\n\t\t\t\tresponse.setContentType(\"text/plain; charset=utf-8\"); \n\t\t\t}\n\t\t\tresponse.getWriter().print(result);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// 执行 \n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "filter" +function_lines = [[130, 182]] +id = "dromara-sa-token-a521eeadf1351e1f" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java" +post_fix = "\tpublic Mono filter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\t\n\t\t// 写入WebFilterChain对象 \n\t\texchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);\n\t\t\n\t\t// ---------- 全局认证处理 \n\t\ttry {\n\t\t\t// 写入全局上下文 (同步) \n\t\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\t\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {\n\t\t\t\texchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);\n\t\t\t}\n\t\t\treturn exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));\n\t\t\t\n\t\t} finally {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t}\n\n\t\t// ---------- 执行\n\n\t\t// 写入全局上下文 (同步) \n\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\n\t\t// 执行 \n\t\treturn chain.filter(exchange).subscriberContext(ctx -> {\n\t\t\t// 写入全局上下文 (异步) \n\t\t\tctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);\n\t\t\treturn ctx;\n\t\t}).doFinally(r -> {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t});\n\t}\n\t\n}" +pre_fix = "\tpublic Mono filter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\t\n\t\t// 写入WebFilterChain对象 \n\t\texchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);\n\t\t\n\t\t// ---------- 全局认证处理 \n\t\ttry {\n\t\t\t// 写入全局上下文 (同步) \n\t\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\t\n\t\t\t// 执行全局过滤器\n\t\t\tbeforeAuth.run(null);\n\t\t\tSaRouter.match(includeList).notMatch(excludeList).check(r -> {\n\t\t\t\tauth.run(null);\n\t\t\t});\n\t\t\t\n\t\t} catch (StopMatchException e) {\n\t\t\t// StopMatchException 异常代表:停止匹配,进入Controller\n\n\t\t} catch (Throwable e) {\n\t\t\t// 1. 获取异常处理策略结果 \n\t\t\tString result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));\n\t\t\t\n\t\t\t// 2. 写入输出流\n\t\t\t// \t\t请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json\n\t\t\t// \t\t例如:SaHolder.getResponse().setHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n\t\t\tif(exchange.getResponse().getHeaders().getFirst(\"Content-Type\") == null) {\n\t\t\t\texchange.getResponse().getHeaders().set(\"Content-Type\", \"text/plain; charset=utf-8\");\n\t\t\t}\n\t\t\treturn exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));\n\t\t\t\n\t\t} finally {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t}\n\n\t\t// ---------- 执行\n\n\t\t// 写入全局上下文 (同步) \n\t\tSaReactorSyncHolder.setContext(exchange);\n\t\t\n\t\t// 执行 \n\t\treturn chain.filter(exchange).subscriberContext(ctx -> {\n\t\t\t// 写入全局上下文 (异步) \n\t\t\tctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);\n\t\t\treturn ctx;\n\t\t}).doFinally(r -> {\n\t\t\t// 清除上下文 \n\t\t\tSaReactorSyncHolder.clearContext();\n\t\t});\n\t}\n\t\n}" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-54f6-9mx9-86f7" +advisory_text = "SaToken privilege escalation vulnerability\n\nAn issue in Dromara SaToken version 1.36.0 and before allows a remote attacker to escalate privileges via a crafted payload to the URL." +commit = "954efeb73277f924f836da2a25322ea35ee1bfa3" +cwe = "CWE-284" +family = "access_control" +function = "getRequestPath" +function_lines = [[127, 134]] +id = "dromara-sa-token-c5b90ba462ff9b12" +language = "java" +method = "fix_site" +parent = "f2416a6175fd4dc30e98a82ddfd7ddcf89c7eb5a" +path = "sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java" +post_fix = "\tpublic String getRequestPath() {\n\t\treturn ApplicationInfo.cutPathPrefix(request.getRequestURI());\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */" +pre_fix = "\tpublic String getRequestPath() {\n\t\treturn request.getServletPath();\n\t}\n\n\t/**\n\t * 返回当前请求的url,例:http://xxx.com/test\n\t * @return see note\n\t */" +repo = "dromara/sa-token" +url = "https://github.com/dromara/Sa-Token.git" + +[[case]] +advisory = "GHSA-6gjm-6wj6-4px5" +advisory_text = "Byobu user preference to prevent private discussions being started are not respected\n\n### Impact\nUsers electing to prevent others starting private discussions with themselves.\n\n> Please note that admins and others with appropriate permissions can always bypass this preference, as was the case before.\n\n### Patches\nUsers of Byobu should update the extension to version 1.1.7, where this has been patched. **This version is only supported on v1.2.0 and later of Flarum Core.**\n\nUsers of Byobu with Flarum 1.0 or 1.1 should upgrade to Flarum 1.2 or later, or evaluate the impact this issue has on your forum's users and choose to disable the extension if needed.\n\n### Workarounds\nThere are no workarounds for this issue." +commit = "23dcf93a30f948d30c678a96681f7fdefeba5171" +cwe = "CWE-863" +family = "access_control" +function = "extend" +function_lines = [[19, 62]] +id = "friendsofflarum-byobu-7173b8a509cf3e27" +language = "javascript" +method = "fix_site" +parent = "2e99cdb7e356a259ea90aa7f84a71fc0f050e006" +path = "js/src/forum/extend/User.js" +post_fix = " extend(UserControls, 'userControls', function (items, user) {\n if (canStartPrivateDiscussion(user)) {\n items.add(\n 'private-discussion',\n Button.component(\n {\n icon: app.forum.attribute('byobu.icon-badge'),\n onclick: (e) => {\n e.preventDefault();\n\n return new Promise((resolve) => {\n let recipients = new ItemList();\n recipients.add('users:' + app.session.user.id(), app.session.user);\n recipients.add('users:' + user.id(), user);\n\n PrivateDiscussionComposer.prototype.recipients = recipients;\n\n app.composer.load(PrivateDiscussionComposer, {\n user: app.session.user,\n recipients: recipients,\n recipientUsers: recipients,\n titlePlaceholder: app.translator.trans('fof-byobu.forum.composer_private_discussion.title_placeholder'),\n submitLabel: app.translator.trans('fof-byobu.forum.composer_private_discussion.submit_button'),\n });\n app.composer.show();\n\n return resolve(app.composer);\n });\n },\n },\n app.translator.trans('fof-byobu.forum.buttons.send_pd', { username: user.username() })\n )\n );\n }\n\n return items;\n });\n}\n" +pre_fix = " extend(UserControls, 'userControls', function (items, user) {\n if (\n app.session.user &&\n app.session.user.id() !== user.id() &&\n app.forum.attribute('canStartPrivateDiscussion') &&\n (user.blocksPd() === false || (app.forum.attribute('canStartPrivateDiscussionWithBlockers') && user.cannotBeDirectMessaged()))\n ) {\n items.add(\n 'private-discussion',\n Button.component(\n {\n icon: app.forum.attribute('byobu.icon-badge'),\n onclick: (e) => {\n e.preventDefault();\n\n return new Promise((resolve) => {\n let recipients = new ItemList();\n recipients.add('users:' + app.session.user.id(), app.session.user);\n recipients.add('users:' + user.id(), user);\n\n PrivateDiscussionComposer.prototype.recipients = recipients;\n\n app.composer.load(PrivateDiscussionComposer, {\n user: app.session.user,\n recipients: recipients,\n recipientUsers: recipients,\n titlePlaceholder: app.translator.trans('fof-byobu.forum.composer_private_discussion.title_placeholder'),\n submitLabel: app.translator.trans('fof-byobu.forum.composer_private_discussion.submit_button'),\n });\n app.composer.show();\n\n return resolve(app.composer);\n });\n },\n },\n app.translator.trans('fof-byobu.forum.buttons.send_pd', { username: user.username() })\n )\n );\n }\n\n return items;\n });\n}\n" +repo = "friendsofflarum/byobu" +url = "https://github.com/FriendsOfFlarum/byobu.git" + +[[case]] +advisory = "GHSA-6gjm-6wj6-4px5" +advisory_text = "Byobu user preference to prevent private discussions being started are not respected\n\n### Impact\nUsers electing to prevent others starting private discussions with themselves.\n\n> Please note that admins and others with appropriate permissions can always bypass this preference, as was the case before.\n\n### Patches\nUsers of Byobu should update the extension to version 1.1.7, where this has been patched. **This version is only supported on v1.2.0 and later of Flarum Core.**\n\nUsers of Byobu with Flarum 1.0 or 1.1 should upgrade to Flarum 1.2 or later, or evaluate the impact this issue has on your forum's users and choose to disable the extension if needed.\n\n### Workarounds\nThere are no workarounds for this issue." +commit = "23dcf93a30f948d30c678a96681f7fdefeba5171" +cwe = "CWE-863" +family = "access_control" +function = "actionItems" +function_lines = [[55, 66]] +id = "friendsofflarum-byobu-f34c4fa78b9178db" +language = "javascript" +method = "fix_site" +parent = "2e99cdb7e356a259ea90aa7f84a71fc0f050e006" +path = "js/src/forum/pages/PrivateDiscussionsUserPage.js" +post_fix = " actionItems() {\n let composing = new PrivateComposing(this.user);\n\n const items = new ItemList();\n\n if (canStartPrivateDiscussion(this.user)) {\n items.add('start_private', composing.component());\n }\n\n return items;\n }\n" +pre_fix = " actionItems() {\n let composing = new PrivateComposing(this.user);\n\n const items = new ItemList();\n\n if (app.session.user && app.forum.attribute('canStartPrivateDiscussion')) {\n items.add('start_private', composing.component());\n }\n\n return items;\n }\n" +repo = "friendsofflarum/byobu" +url = "https://github.com/FriendsOfFlarum/byobu.git" + +[[case]] +advisory = "GHSA-3j8f-xvm3-ffx4" +advisory_text = "Authorization Bypass in parse-path\n\nAuthorization Bypass Through User-Controlled Key in GitHub repository ionicabizau/parse-path prior to 5.0.0." +commit = "f9ad8856a3c8ae18e1cf4caef5edbabbc42840e8" +cwe = "CWE-639" +family = "access_control" +function = "parsePath" +function_lines = [[27, 135]] +id = "ionicabizau-parse-path-48d212f285d46f4b" +language = "javascript" +method = "fix_site" +parent = "3795a3cda744b599a9247cca35395be4f3635b1b" +path = "lib/index.js" +post_fix = "function parsePath(url) {\n\n const output = {\n protocols: []\n , protocol: null\n , port: null\n , resource: \"\"\n , user: \"\"\n , password: \"\"\n , pathname: \"\"\n , hash: \"\"\n , search: \"\"\n , href: url\n , query: {}\n }\n\n try {\n const parsed = new URL(url)\n output.protocols = protocols(parsed)\n output.protocol = output.protocols[0]\n output.port = parsed.port\n output.resource = parsed.host\n output.user = parsed.username || \"\"\n output.password = parsed.password || \"\"\n output.pathname = parsed.pathname\n output.hash = parsed.hash.slice(1)\n output.search = parsed.search.slice(1)\n output.href = parsed.href\n output.query = Object.fromEntries(parsed.searchParams)\n } catch (e) {\n // TODO Maybe check if it is a valid local file path\n // In any case, these will be parsed by higher\n // level parsers such as parse-url, git-url-parse, git-up\n output.protocols = [\"file\"]\n output.protocol = output.protocols[0]\n output.port = \"\"\n output.resource = \"\"\n output.user = \"\"\n output.pathname = \"\"\n output.hash = \"\"\n output.search = \"\"\n output.href = url\n output.query = {}\n }\n\n return output;\n}\n\nmodule.exports = parsePath;" +pre_fix = "function parsePath(url) {\n url = (url || \"\").trim().replace(/\\r?\\n|\\r/gm, \"\")\n var output = {\n protocols: protocols(url)\n , protocol: null\n , port: null\n , resource: \"\"\n , user: \"\"\n , pathname: \"\"\n , hash: \"\"\n , search: \"\"\n , href: url\n , query: Object.create(null)\n }\n , protocolIndex = url.indexOf(\"://\")\n , resourceIndex = -1\n , splits = null\n , parts = null\n ;\n\n if (url.startsWith(\".\")) {\n if (url.startsWith(\"./\")) {\n url = url.substring(2);\n }\n output.pathname = url;\n output.protocol = \"file\";\n }\n\n const firstChar = url.charAt(1)\n if (!output.protocol) {\n output.protocol = output.protocols[0]\n if (!output.protocol) {\n if (isSsh(url)) {\n output.protocol = \"ssh\"\n } else if (firstChar === \"/\" || firstChar === \"~\") {\n url = url.substring(2)\n output.protocol = \"file\"\n } else {\n output.protocol = \"file\"\n }\n }\n }\n\n if (protocolIndex !== -1) {\n url = url.substring(protocolIndex + 3);\n }\n\n parts = url.split(/\\/|\\\\/);\n if (output.protocol !== \"file\") {\n output.resource = parts.shift();\n } else {\n output.resource = \"\";\n }\n\n // user@domain\n splits = output.resource.split(\"@\");\n if (splits.length === 2) {\n output.user = splits[0];\n output.resource = splits[1];\n }\n\n\n // domain.com:port\n splits = output.resource.split(\":\");\n if (splits.length === 2) {\n output.resource = splits[0];\n const port = splits[1];\n if (port) {\n output.port = Number(port);\n if (isNaN(output.port) || port.match(/^\\d+$/) === null) {\n output.port = null;\n parts.unshift(port);\n }\n } else {\n output.port = null\n }\n }\n\n // Remove empty elements\n parts = parts.filter(Boolean);\n\n // Stringify the pathname\n if (output.protocol === \"file\") {\n output.pathname = output.href\n } else {\n output.pathname = output.pathname || ((output.protocol !== \"file\" || output.href[0] === \"/\" ? \"/\" : \"\") + parts.join(\"/\"));\n }\n\n // #some-hash\n splits = output.pathname.split(\"#\");\n if (splits.length === 2) {\n output.pathname = splits[0];\n output.hash = splits[1];\n }\n\n // ?foo=bar\n splits = output.pathname.split(\"?\");\n if (splits.length === 2) {\n output.pathname = splits[0];\n output.search = splits[1];\n }\n\n output.query = qs.parse(output.search);\n output.href = output.href.replace(/\\/$/, \"\")\n output.pathname = output.pathname.replace(/\\/$/, \"\")\n return output;\n}\n\nmodule.exports = parsePath;" +repo = "ionicabizau/parse-path" +url = "https://github.com/IonicaBizau/parse-path.git" + +[[case]] +advisory = "GHSA-vvfj-p4jf-j8rm" +advisory_text = "Missing permission check in Jenkins Static Analysis Utilities Plugin\n\nA missing permission check in Jenkins Static Analysis Utilities Plugin 1.95 and earlier in the DefaultGraphConfigurationView#doSave form handler method allowed attackers with Overall/Read permission to change the per-job default graph configuration for all users." +commit = "3d7a0c7907d831c58541508b893dcea2039809c5" +cwe = "CWE-862" +family = "access_control" +function = "persistValue" +function_lines = [[126, 136]] +id = "jenkinsci-analysis-core-plugin-e02e86e3c18ec1d6" +language = "java" +method = "fix_site" +parent = "892ab94f85a49d8c04b302c9bf48b112efe97536" +path = "src/main/java/hudson/plugins/analysis/graph/DefaultGraphConfigurationView.java" +post_fix = " protected void persistValue(final String value, final String pluginName, final StaplerRequest request, final StaplerResponse response) throws FileNotFoundException, IOException {\n FileOutputStream output = new FileOutputStream(createDefaultsFile(getOwner(), pluginName));\n try {\n IOUtils.write(value, output);\n }\n finally {\n output.close();\n }\n }\n\n @Override" +pre_fix = " protected void persistValue(final String value, final String pluginName, final StaplerRequest request, final StaplerResponse response) throws FileNotFoundException, IOException {\n FileOutputStream output = new FileOutputStream(createDefaultsFile(getOwner(), pluginName));\n try {\n IOUtils.write(value, output);\n }\n finally {\n output.close();\n }\n }\n}\n" +repo = "jenkinsci/analysis-core-plugin" +url = "https://github.com/jenkinsci/analysis-core-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "doVerifyConfiguration" +function_lines = [[46, 64]] +id = "jenkinsci-azure-credentials-plugin-0dab78b4ed2c29bb" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/jenkins/keyvault/SecretStringCredentials.java" +post_fix = " public FormValidation doVerifyConfiguration(\n @AncestorInPath Item owner,\n @QueryParameter String servicePrincipalId,\n @QueryParameter String secretIdentifier) {\n if (owner == null) {\n Jenkins.get().checkPermission(Jenkins.ADMINISTER);\n } else {\n owner.checkPermission(Item.CONFIGURE);\n }\n\n final SecretStringCredentials credentials = new SecretStringCredentials(\n CredentialsScope.SYSTEM, \"\", \"\", servicePrincipalId, secretIdentifier);\n\n try {\n credentials.getSecret();\n } catch (Exception e) {\n String message = e.getMessage();\n if (message == null) {\n message = Messages.String_Credentials_Validation_Invalid();\n }\n return FormValidation.error(message);\n }\n\n return FormValidation.ok(Messages.String_Credentials_Validation_OK());\n }" +pre_fix = " public FormValidation doVerifyConfiguration(\n @QueryParameter String servicePrincipalId,\n @QueryParameter String secretIdentifier) {\n\n final SecretStringCredentials credentials = new SecretStringCredentials(\n CredentialsScope.SYSTEM, \"\", \"\", servicePrincipalId, secretIdentifier);\n\n try {\n credentials.getSecret();\n } catch (Exception e) {\n String message = e.getMessage();\n if (message == null) {\n message = Messages.String_Credentials_Validation_Invalid();\n }\n return FormValidation.error(message);\n }\n\n return FormValidation.ok(Messages.String_Credentials_Validation_OK());\n }" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "doFillServicePrincipalIdItems" +function_lines = [[97, 103]] +id = "jenkinsci-azure-credentials-plugin-144d42edd4fea476" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/jenkins/keyvault/BaseSecretCredentials.java" +post_fix = " public ListBoxModel doFillServicePrincipalIdItems(\n @AncestorInPath Item owner,\n @QueryParameter(\"servicePrincipalId\") String servicePrincipalId) {\n StandardListBoxModel model = new StandardListBoxModel();\n model.includeEmptyValue();\n if (owner == null) {\n if (!Jenkins.get().hasPermission(CredentialsProvider.CREATE)\n && !Jenkins.get().hasPermission(CredentialsProvider.UPDATE)) {\n return model.includeCurrentValue(servicePrincipalId);\n }\n } else {\n if (!owner.hasPermission(CredentialsProvider.CREATE)\n && !owner.hasPermission(CredentialsProvider.UPDATE)) {\n return model.includeCurrentValue(servicePrincipalId);\n }\n }\n return model\n .includeCurrentValue(servicePrincipalId)\n .includeAs(Jenkins.getAuthentication(), owner, AzureCredentials.class)\n .includeAs(ACL.SYSTEM, owner, AzureCredentials.class);\n }" +pre_fix = " public ListBoxModel doFillServicePrincipalIdItems(Item owner) {\n return new StandardListBoxModel()\n .includeEmptyValue()\n .includeAs(ACL.SYSTEM, owner, AzureCredentials.class);\n }\n }\n}" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "getCertificate" +function_lines = [[149, 165]] +id = "jenkinsci-azure-credentials-plugin-36e89cc01c1af07f" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/azure/util/AzureCredentials.java" +post_fix = " CertificateCredentialsImpl getCertificate() {\n if (StringUtils.isNotEmpty(clientSecret.getPlainText())) {\n return null;\n }\n if (StringUtils.isEmpty(certificateId)) {\n return null;\n }\n CertificateCredentialsImpl certificate = getCredentials(\n CertificateCredentialsImpl.class,\n certificateId, ACL.SYSTEM);\n if (certificate == null) {\n return getCredentials(\n CertificateCredentialsImpl.class,\n certificateId, Jenkins.getAuthentication());\n }\n return null;\n }\n\n @Nullable" +pre_fix = " CertificateCredentialsImpl getCertificate() {\n if (StringUtils.isNotEmpty(clientSecret.getPlainText())) {\n return null;\n }\n if (StringUtils.isEmpty(certificateId)) {\n return null;\n }\n return CredentialsMatchers.firstOrNull(\n CredentialsProvider.lookupCredentials(\n CertificateCredentialsImpl.class,\n Jenkins.get(),\n ACL.SYSTEM,\n Collections.emptyList()),\n CredentialsMatchers.withId(certificateId));\n }\n\n @Nullable" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "doVerifyConfiguration" +function_lines = [[772, 800]] +id = "jenkinsci-azure-credentials-plugin-81c51344b9d31af8" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/azure/util/AzureCredentials.java" +post_fix = " public FormValidation doVerifyConfiguration(\n @AncestorInPath Item owner,\n @QueryParameter String subscriptionId,\n @QueryParameter String clientId,\n @QueryParameter String clientSecret,\n @QueryParameter String certificateId,\n @QueryParameter String tenant,\n @QueryParameter String azureEnvironmentName,\n @QueryParameter String serviceManagementURL,\n @QueryParameter String authenticationEndpoint,\n @QueryParameter String resourceManagerEndpoint,\n @QueryParameter String graphEndpoint) {\n if (owner == null) {\n Jenkins.get().checkPermission(Jenkins.ADMINISTER);\n } else {\n owner.checkPermission(Item.CONFIGURE);\n }\n\n AzureCredentials.ServicePrincipal servicePrincipal\n = new AzureCredentials.ServicePrincipal(subscriptionId, clientId, Secret.fromString(clientSecret));\n servicePrincipal.setCertificateId(certificateId);\n servicePrincipal.setTenant(tenant);\n servicePrincipal.setAzureEnvironmentName(azureEnvironmentName);\n servicePrincipal.setManagementEndpoint(serviceManagementURL);\n servicePrincipal.setActiveDirectoryEndpoint(authenticationEndpoint);\n servicePrincipal.setResourceManagerEndpoint(resourceManagerEndpoint);\n servicePrincipal.setGraphEndpoint(graphEndpoint);\n try {\n servicePrincipal.validate();\n } catch (ValidationException e) {\n return FormValidation.error(e, e.getMessage());\n }\n\n return FormValidation.ok(Messages.Azure_Config_Success());\n }" +pre_fix = " public FormValidation doVerifyConfiguration(\n @QueryParameter String subscriptionId,\n @QueryParameter String clientId,\n @QueryParameter String clientSecret,\n @QueryParameter String certificateId,\n @QueryParameter String tenant,\n @QueryParameter String azureEnvironmentName,\n @QueryParameter String serviceManagementURL,\n @QueryParameter String authenticationEndpoint,\n @QueryParameter String resourceManagerEndpoint,\n @QueryParameter String graphEndpoint) {\n\n AzureCredentials.ServicePrincipal servicePrincipal\n = new AzureCredentials.ServicePrincipal(subscriptionId, clientId, Secret.fromString(clientSecret));\n servicePrincipal.setCertificateId(certificateId);\n servicePrincipal.setTenant(tenant);\n servicePrincipal.setAzureEnvironmentName(azureEnvironmentName);\n servicePrincipal.setManagementEndpoint(serviceManagementURL);\n servicePrincipal.setActiveDirectoryEndpoint(authenticationEndpoint);\n servicePrincipal.setResourceManagerEndpoint(resourceManagerEndpoint);\n servicePrincipal.setGraphEndpoint(graphEndpoint);\n try {\n servicePrincipal.validate();\n } catch (ValidationException e) {\n return FormValidation.error(e, e.getMessage());\n }\n\n return FormValidation.ok(Messages.Azure_Config_Success());\n }" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "doFillCertificateIdItems" +function_lines = [[802, 808]] +id = "jenkinsci-azure-credentials-plugin-a83f939fb055e6a0" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/azure/util/AzureCredentials.java" +post_fix = " public ListBoxModel doFillCertificateIdItems(\n @AncestorInPath Item owner,\n @QueryParameter(\"certificateId\") String certificateId) {\n StandardListBoxModel model = new StandardListBoxModel();\n model.add(Messages.Azure_Credentials_Select(), \"\");\n if (owner == null) {\n if (!Jenkins.get().hasPermission(CredentialsProvider.CREATE)\n && !Jenkins.get().hasPermission(CredentialsProvider.UPDATE)) {\n return model.includeCurrentValue(certificateId);\n }\n } else {\n if (!owner.hasPermission(CredentialsProvider.CREATE)\n && !owner.hasPermission(CredentialsProvider.UPDATE)) {\n return model.includeCurrentValue(certificateId);\n }\n }\n\n return model\n .includeCurrentValue(certificateId)\n .includeAs(Jenkins.getAuthentication(), owner, CertificateCredentialsImpl.class)\n .includeAs(ACL.SYSTEM, owner, CertificateCredentialsImpl.class);\n }" +pre_fix = " public ListBoxModel doFillCertificateIdItems(@AncestorInPath Item owner) {\n StandardListBoxModel model = new StandardListBoxModel();\n model.add(Messages.Azure_Credentials_Select(), \"\");\n model.includeAs(ACL.SYSTEM, owner, CertificateCredentialsImpl.class);\n return model;\n }\n" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "doVerifyConfiguration" +function_lines = [[105, 134]] +id = "jenkinsci-azure-credentials-plugin-af7645f7ae48e24c" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/jenkins/keyvault/SecretCertificateCredentials.java" +post_fix = " public FormValidation doVerifyConfiguration(\n @AncestorInPath Item owner,\n @QueryParameter String servicePrincipalId,\n @QueryParameter String secretIdentifier,\n @QueryParameter Secret password) {\n if (owner == null) {\n Jenkins.get().checkPermission(Jenkins.ADMINISTER);\n } else {\n owner.checkPermission(Item.CONFIGURE);\n }\n\n final SecretCertificateCredentials credentials = new SecretCertificateCredentials(\n CredentialsScope.SYSTEM, \"\", \"\", servicePrincipalId, secretIdentifier, password);\n\n KeyStore keyStore;\n try {\n keyStore = credentials.getKeyStore();\n } catch (Exception e) {\n String message = e.getMessage();\n if (message == null) {\n message = Messages.Certificate_Credentials_Validation_Invalid();\n }\n return FormValidation.error(message);\n }\n\n try {\n final Enumeration aliases = keyStore.aliases();\n if (!aliases.hasMoreElements()) {\n return FormValidation.error(Messages.Certificate_Credentials_Validation_No_Private_Key());\n }\n } catch (KeyStoreException e) {\n return FormValidation.error(e.getMessage());\n }\n\n return FormValidation.ok(Messages.Certificate_Credentials_Validation_OK());\n }" +pre_fix = " public FormValidation doVerifyConfiguration(\n @QueryParameter String servicePrincipalId,\n @QueryParameter String secretIdentifier,\n @QueryParameter Secret password) {\n\n final SecretCertificateCredentials credentials = new SecretCertificateCredentials(\n CredentialsScope.SYSTEM, \"\", \"\", servicePrincipalId, secretIdentifier, password);\n\n KeyStore keyStore;\n try {\n keyStore = credentials.getKeyStore();\n } catch (Exception e) {\n String message = e.getMessage();\n if (message == null) {\n message = Messages.Certificate_Credentials_Validation_Invalid();\n }\n return FormValidation.error(message);\n }\n\n try {\n final Enumeration aliases = keyStore.aliases();\n if (!aliases.hasMoreElements()) {\n return FormValidation.error(Messages.Certificate_Credentials_Validation_No_Private_Key());\n }\n } catch (KeyStoreException e) {\n return FormValidation.error(e.getMessage());\n }\n\n return FormValidation.ok(Messages.Certificate_Credentials_Validation_OK());\n }" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "validate" +function_lines = [[55, 94]] +id = "jenkinsci-azure-credentials-plugin-bd1228731e6d22aa" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/azure/util/AzureImdsCredentials.java" +post_fix = " public boolean validate() throws AzureCredentials.ValidationException {\n try {\n final String credentialSubscriptionId = getSubscriptionId();\n\n AzureProfile profile = new AzureProfile(AzureEnvUtil.resolveAzureEnv(getAzureEnvName()));\n ManagedIdentityCredentialBuilder credentialBuilder = new ManagedIdentityCredentialBuilder();\n\n if (getClientId() != null) {\n credentialBuilder.clientId(getClientId());\n }\n\n AzureResourceManager azure = AzureResourceManager\n .configure()\n .withRetryPolicy(getRetryPolicy())\n .withHttpClient(HttpClientRetriever.get())\n .authenticate(credentialBuilder.build(), profile)\n .withSubscription(credentialSubscriptionId);\n\n PagedIterable subscriptions = azure.subscriptions().list();\n\n if (subscriptionId != null) {\n for (Subscription subscription : subscriptions) {\n if (subscription.subscriptionId().equalsIgnoreCase(credentialSubscriptionId)) {\n return true;\n }\n }\n } else {\n return true;\n }\n } catch (Exception e) {\n throw new AzureCredentials.ValidationException(Messages.Azure_CantValidate() + \": \" + e.getMessage(), e);\n }\n throw new AzureCredentials.ValidationException(Messages.Azure_Invalid_SubscriptionId());\n }\n" +pre_fix = " public boolean validate() throws AzureCredentials.ValidationException {\n try {\n final String credentialSubscriptionId = getSubscriptionId();\n\n AzureProfile profile = new AzureProfile(AzureEnvUtil.resolveAzureEnv(getAzureEnvName()));\n ManagedIdentityCredentialBuilder credentialBuilder = new ManagedIdentityCredentialBuilder();\n\n if (getClientId() != null) {\n credentialBuilder.clientId(getClientId());\n }\n\n AzureResourceManager azure = AzureResourceManager\n .configure()\n .withHttpClient(HttpClientRetriever.get())\n .authenticate(credentialBuilder.build(), profile)\n .withSubscription(credentialSubscriptionId);\n\n PagedIterable subscriptions = azure.subscriptions().list();\n\n if (subscriptionId != null) {\n for (Subscription subscription : subscriptions) {\n if (subscription.subscriptionId().equalsIgnoreCase(credentialSubscriptionId)) {\n return true;\n }\n }\n } else {\n return true;\n }\n } catch (Exception e) {\n throw new AzureCredentials.ValidationException(Messages.Azure_CantValidate() + \": \" + e.getMessage(), e);\n }\n throw new AzureCredentials.ValidationException(Messages.Azure_Invalid_SubscriptionId());\n }\n\n\n @Extension\n public static class DescriptorImpl\n extends BaseStandardCredentials.BaseStandardCredentialsDescriptor {\n\n @Override" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-7j55-28qq-676g" +advisory_text = "Missing Authorization in Jenkins Azure Credentials Plugin\n\nA missing permission check in Jenkins Azure Credentials Plugin 253.v887e0f9e898b and earlier allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "64da8176c83a41bb83d3ad759628c9bd275b42f5" +cwe = "CWE-862" +family = "access_control" +function = "doVerifyConfiguration" +function_lines = [[107, 128]] +id = "jenkinsci-azure-credentials-plugin-d3c1129ce0199756" +language = "java" +method = "fix_site" +parent = "887e0f9e898b2765d78e53c7b39017b8d6295dca" +path = "src/main/java/com/microsoft/azure/util/AzureImdsCredentials.java" +post_fix = " public FormValidation doVerifyConfiguration(\n @AncestorInPath Item owner,\n @QueryParameter String subscriptionId,\n @QueryParameter String clientId,\n @QueryParameter String azureEnvironmentName) {\n if (owner == null) {\n Jenkins.get().checkPermission(Jenkins.ADMINISTER);\n } else {\n owner.checkPermission(Item.CONFIGURE);\n }\n\n AzureImdsCredentials imdsCredentials = new AzureImdsCredentials(null, null, null, azureEnvironmentName);\n if (StringUtils.isNotBlank(subscriptionId)) {\n imdsCredentials.setSubscriptionId(subscriptionId);\n }\n\n if (StringUtils.isNotBlank(clientId)) {\n imdsCredentials.setClientId(clientId);\n }\n\n try {\n imdsCredentials.validate();\n } catch (AzureCredentials.ValidationException e) {\n return FormValidation.error(e.getMessage());\n }\n\n return FormValidation.ok(Messages.Azure_MI_Config_Success());\n }" +pre_fix = " public FormValidation doVerifyConfiguration(\n @QueryParameter String subscriptionId,\n @QueryParameter String clientId,\n @QueryParameter String azureEnvironmentName) {\n\n AzureImdsCredentials imdsCredentials = new AzureImdsCredentials(null, null, null, azureEnvironmentName);\n if (StringUtils.isNotBlank(subscriptionId)) {\n imdsCredentials.setSubscriptionId(subscriptionId);\n }\n\n if (StringUtils.isNotBlank(clientId)) {\n imdsCredentials.setClientId(clientId);\n }\n\n try {\n imdsCredentials.validate();\n } catch (AzureCredentials.ValidationException e) {\n return FormValidation.error(e.getMessage());\n }\n\n return FormValidation.ok(Messages.Azure_MI_Config_Success());\n }" +repo = "jenkinsci/azure-credentials-plugin" +url = "https://github.com/jenkinsci/azure-credentials-plugin.git" + +[[case]] +advisory = "GHSA-gf8w-6hcm-rh3j" +advisory_text = "Missing permission checks in Jenkins Azure Key Vault Plugin allow enumerating credentials IDs\n\nJenkins Azure Key Vault Plugin 2.0 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins. Those can be used as part of an attack to capture the credentials using another vulnerability.\n\nAn enumeration of credentials IDs in Jenkins Azure Key Vault Plugin 2.1 requires the appropriate permissions." +commit = "f09ed652cc572d8ba5d7c8c8f9972fd241883c21" +cwe = "CWE-862" +family = "access_control" +function = "convertAndWritePfxToDisk" +function_lines = [[44, 75]] +id = "jenkinsci-azure-keyvault-plugin-344db7c550754ab3" +language = "java" +method = "fix_site" +parent = "36680c54a27685d6d35d75135daa6e386a107a1b" +path = "src/main/java/org/jenkinsci/plugins/azurekeyvaultplugin/AzureKeyVaultUtil.java" +post_fix = " static String convertAndWritePfxToDisk(FilePath workspace, String secret)\n throws IOException, GeneralSecurityException, InterruptedException {\n // Base64 decode the result and use a keystore to parse the key/cert\n byte[] bytes = DatatypeConverter.parseBase64Binary(secret);\n KeyStore ks = KeyStore.getInstance(PKCS12);\n ks.load(new ByteArrayInputStream(bytes), EMPTY_CHAR_ARRAY);\n\n // Extract the key(s) and cert(s) and save them in a *second* keystore\n // because the first keystore yields a corrupted PFX when written to disk\n KeyStore ks2 = KeyStore.getInstance(PKCS12);\n ks2.load(null, null);\n\n for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) {\n String alias = e.nextElement();\n Certificate[] chain = ks.getCertificateChain(alias);\n Key privateKey = ks.getKey(alias, EMPTY_CHAR_ARRAY);\n ks2.setKeyEntry(alias, privateKey, EMPTY_CHAR_ARRAY, chain);\n }\n\n // ensure workspace has been created\n workspace.mkdirs();\n\n // Write PFX to disk on executor, which may be a separate physical system\n FilePath outFile = workspace.createTempFile(\"keyvault-\", \".pfx\");\n try (OutputStream outFileStream = outFile.write()) {\n ks2.store(outFileStream, EMPTY_CHAR_ARRAY);\n }\n\n URI uri = outFile.toURI();\n return uri.getPath();\n }\n" +pre_fix = " static String convertAndWritePfxToDisk(FilePath workspace, String secret)\n throws IOException, GeneralSecurityException, InterruptedException {\n // Base64 decode the result and use a keystore to parse the key/cert\n byte[] bytes = DatatypeConverter.parseBase64Binary(secret);\n KeyStore ks = KeyStore.getInstance(PKCS12);\n ks.load(new ByteArrayInputStream(bytes), EMPTY_CHAR_ARRAY);\n\n // Extract the key(s) and cert(s) and save them in a *second* keystore\n // because the first keystore yields a corrupted PFX when written to disk\n KeyStore ks2 = KeyStore.getInstance(PKCS12);\n ks2.load(null, null);\n\n for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) {\n String alias = e.nextElement();\n Certificate[] chain = ks.getCertificateChain(alias);\n Key privateKey = ks.getKey(alias, EMPTY_CHAR_ARRAY);\n ks2.setKeyEntry(alias, privateKey, EMPTY_CHAR_ARRAY, chain);\n }\n\n // ensure workspace has been created\n workspace.mkdirs();\n\n // Write PFX to disk on executor, which may be a separate physical system\n FilePath outFile = workspace.createTempFile(\"keyvault-\", \".pfx\");\n try (OutputStream outFileStream = outFile.write()) {\n ks2.store(outFileStream, EMPTY_CHAR_ARRAY);\n }\n\n URI uri = outFile.toURI();\n return uri.getPath();\n }\n}" +repo = "jenkinsci/azure-keyvault-plugin" +url = "https://github.com/jenkinsci/azure-keyvault-plugin.git" + +[[case]] +advisory = "GHSA-gf8w-6hcm-rh3j" +advisory_text = "Missing permission checks in Jenkins Azure Key Vault Plugin allow enumerating credentials IDs\n\nJenkins Azure Key Vault Plugin 2.0 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins. Those can be used as part of an attack to capture the credentials using another vulnerability.\n\nAn enumeration of credentials IDs in Jenkins Azure Key Vault Plugin 2.1 requires the appropriate permissions." +commit = "f09ed652cc572d8ba5d7c8c8f9972fd241883c21" +cwe = "CWE-862" +family = "access_control" +function = "SuppressWarnings" +function_lines = [[290, 295]] +id = "jenkinsci-azure-keyvault-plugin-a9975f6d8b4f1568" +language = "java" +method = "fix_site" +parent = "36680c54a27685d6d35d75135daa6e386a107a1b" +path = "src/main/java/org/jenkinsci/plugins/azurekeyvaultplugin/AzureKeyVaultBuildWrapper.java" +post_fix = " @SuppressWarnings(\"unused\")\n @POST\n public ListBoxModel doFillCredentialIDOverrideItems(@AncestorInPath Item context) {\n return AzureKeyVaultUtil.doFillCredentialIDItems(context);\n }" +pre_fix = " @SuppressWarnings(\"unused\")\n public ListBoxModel doFillCredentialIDOverrideItems(@AncestorInPath Item context) {\n return new StandardListBoxModel().includeEmptyValue()\n .includeAs(ACL.SYSTEM, context, AzureImdsCredentials.class)\n .includeAs(ACL.SYSTEM, context, AzureCredentials.class);\n }" +repo = "jenkinsci/azure-keyvault-plugin" +url = "https://github.com/jenkinsci/azure-keyvault-plugin.git" + +[[case]] +advisory = "GHSA-gf8w-6hcm-rh3j" +advisory_text = "Missing permission checks in Jenkins Azure Key Vault Plugin allow enumerating credentials IDs\n\nJenkins Azure Key Vault Plugin 2.0 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins. Those can be used as part of an attack to capture the credentials using another vulnerability.\n\nAn enumeration of credentials IDs in Jenkins Azure Key Vault Plugin 2.1 requires the appropriate permissions." +commit = "f09ed652cc572d8ba5d7c8c8f9972fd241883c21" +cwe = "CWE-862" +family = "access_control" +function = "SuppressWarnings" +function_lines = [[218, 223]] +id = "jenkinsci-azure-keyvault-plugin-abd182ce20617255" +language = "java" +method = "fix_site" +parent = "36680c54a27685d6d35d75135daa6e386a107a1b" +path = "src/main/java/org/jenkinsci/plugins/azurekeyvaultplugin/AzureKeyVaultStep.java" +post_fix = " @SuppressWarnings(\"unused\")\n @POST\n public ListBoxModel doFillCredentialIDItems(@AncestorInPath Item context) {\n return AzureKeyVaultUtil.doFillCredentialIDItems(context);\n }" +pre_fix = " @SuppressWarnings(\"unused\")\n public ListBoxModel doFillCredentialIDItems(@AncestorInPath Item context) {\n return new StandardListBoxModel().includeEmptyValue()\n .includeAs(ACL.SYSTEM, context, AzureImdsCredentials.class)\n .includeAs(ACL.SYSTEM, context, AzureCredentials.class);\n }" +repo = "jenkinsci/azure-keyvault-plugin" +url = "https://github.com/jenkinsci/azure-keyvault-plugin.git" + +[[case]] +advisory = "GHSA-vc7g-4269-f7hw" +advisory_text = "Missing permission check in Blue Ocean Plugin\n\n### Updated 2020-09-16\nThis entry previously misidentified the problematic behavior. The HTTP request itself is legitimate, but only authorized users should be able to perform it.\n\n### Original Description\nBlue Ocean Plugin 1.23.2 and earlier does not perform permission checks in several HTTP endpoints implementing connection tests.\n\nThis allows attackers with Overall/Read permission to connect to an attacker-specified URL.\n\nBlue Ocean Plugin 1.23.3 requires Item/Create permission to perform these connection tests." +commit = "659a66aff0d0ad693eab9d2807985d591e102aab" +cwe = "CWE-862" +family = "access_control" +function = "create" +function_lines = [[56, 145]] +id = "jenkinsci-blueocean-plugin-5aa4f2eb0a53ebfe" +language = "java" +method = "fix_site" +parent = "966da5a824c0e78767ba8b6a40be2ebfd8d8919f" +path = "blueocean-github-pipeline/src/main/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubServerContainer.java" +post_fix = " public @CheckForNull ScmServerEndpoint create(@JsonBody JSONObject request) {\n\n try {\n Jenkins.get().checkPermission(Item.CREATE);\n } catch (Exception e) {\n throw new ServiceException.ForbiddenException(\"User does not have permission to create repository.\", e);\n }\n\n List errors = new LinkedList();\n\n // Validate name\n final String name = (String) request.get(GithubServer.NAME);\n if (StringUtils.isEmpty(name)) {\n errors.add(new ErrorMessage.Error(GithubServer.NAME, ErrorMessage.Error.ErrorCodes.MISSING.toString(), GithubServer.NAME + \" is required\"));\n } else {\n GithubServer byName = findByName(name);\n if (byName != null) {\n errors.add(new ErrorMessage.Error(GithubServer.NAME, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), GithubServer.NAME + \" already exists for server at '\" + byName.getApiUrl() + \"'\"));\n }\n }\n\n // Validate url\n final String url = (String) request.get(GithubServer.API_URL);\n if (StringUtils.isEmpty(url)) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.MISSING.toString(), GithubServer.API_URL + \" is required\"));\n } else {\n Endpoint byUrl = GitHubConfiguration.get().findEndpoint(url);\n if (byUrl != null) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), GithubServer.API_URL + \" is already registered as '\" + byUrl.getName() + \"'\"));\n }\n }\n\n if (StringUtils.isNotEmpty(url)) {\n // Validate that the URL represents a GitHub API endpoint\n try {\n HttpURLConnection connection = HttpRequest.get(url).connect();\n\n if (connection.getHeaderField(\"X-GitHub-Request-Id\") == null) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), ERROR_MESSAGE_INVALID_SERVER));\n } else {\n boolean isGithubCloud = false;\n boolean isGithubEnterprise = false;\n\n try {\n InputStream inputStream;\n int code = connection.getResponseCode();\n\n if (200 <= code && code < 300) {\n inputStream = HttpRequest.getInputStream(connection);\n } else {\n inputStream = HttpRequest.getErrorStream(connection);\n }\n\n TypeReference> typeRef = new TypeReference>(){};\n Map responseBody = GithubScm.getMappingObjectReader().forType(typeRef).readValue(inputStream);\n\n isGithubCloud = code == 200 && responseBody.containsKey(\"current_user_url\");\n isGithubEnterprise = code == 401 && responseBody.containsKey(\"message\");\n } catch (IllegalArgumentException | IOException ioe) {\n LOGGER.log(Level.INFO, \"Could not parse response body from Github\");\n }\n\n if (!isGithubCloud && !isGithubEnterprise) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), ERROR_MESSAGE_INVALID_APIURL));\n }\n }\n } catch (Throwable e) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), e.toString()));\n LOGGER.log(Level.INFO, \"Could not connect to Github\", e);\n }\n }\n\n if (errors.isEmpty()) {\n SecurityContext old = null;\n try {\n // We need to escalate privilege to add user defined endpoint to\n old = ACL.impersonate(ACL.SYSTEM);\n GitHubConfiguration config = GitHubConfiguration.get();\n String sanitizedUrl = discardQueryString(url);\n Endpoint endpoint = new Endpoint(sanitizedUrl, name);\n if (!config.addEndpoint(endpoint)) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), GithubServer.API_URL + \" is already registered as '\" + endpoint.getName() + \"'\"));\n } else {\n return new GithubServer(endpoint, getLink());\n }\n }finally {\n //reset back to original privilege level\n if(old != null){\n SecurityContextHolder.setContext(old);\n }\n }\n }\n ErrorMessage message = new ErrorMessage(400, \"Failed to create GitHub server\");\n message.addAll(errors);\n throw new ServiceException.BadRequestException(message);\n }" +pre_fix = " public @CheckForNull ScmServerEndpoint create(@JsonBody JSONObject request) {\n\n List errors = Lists.newLinkedList();\n\n // Validate name\n final String name = (String) request.get(GithubServer.NAME);\n if (StringUtils.isEmpty(name)) {\n errors.add(new ErrorMessage.Error(GithubServer.NAME, ErrorMessage.Error.ErrorCodes.MISSING.toString(), GithubServer.NAME + \" is required\"));\n } else {\n GithubServer byName = findByName(name);\n if (byName != null) {\n errors.add(new ErrorMessage.Error(GithubServer.NAME, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), GithubServer.NAME + \" already exists for server at '\" + byName.getApiUrl() + \"'\"));\n }\n }\n\n // Validate url\n final String url = (String) request.get(GithubServer.API_URL);\n if (StringUtils.isEmpty(url)) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.MISSING.toString(), GithubServer.API_URL + \" is required\"));\n } else {\n Endpoint byUrl = GitHubConfiguration.get().findEndpoint(url);\n if (byUrl != null) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), GithubServer.API_URL + \" is already registered as '\" + byUrl.getName() + \"'\"));\n }\n }\n\n if (StringUtils.isNotEmpty(url)) {\n // Validate that the URL represents a GitHub API endpoint\n try {\n HttpURLConnection connection = HttpRequest.get(url).connect();\n\n if (connection.getHeaderField(\"X-GitHub-Request-Id\") == null) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), ERROR_MESSAGE_INVALID_SERVER));\n } else {\n boolean isGithubCloud = false;\n boolean isGithubEnterprise = false;\n\n try {\n InputStream inputStream;\n int code = connection.getResponseCode();\n\n if (200 <= code && code < 300) {\n inputStream = HttpRequest.getInputStream(connection);\n } else {\n inputStream = HttpRequest.getErrorStream(connection);\n }\n\n TypeReference> typeRef = new TypeReference>(){};\n Map responseBody = GithubScm.getMappingObjectReader().forType(typeRef).readValue(inputStream);\n\n isGithubCloud = code == 200 && responseBody.containsKey(\"current_user_url\");\n isGithubEnterprise = code == 401 && responseBody.containsKey(\"message\");\n } catch (IllegalArgumentException | IOException ioe) {\n LOGGER.log(Level.INFO, \"Could not parse response body from Github\");\n }\n\n if (!isGithubCloud && !isGithubEnterprise) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), ERROR_MESSAGE_INVALID_APIURL));\n }\n }\n } catch (Throwable e) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), e.toString()));\n LOGGER.log(Level.INFO, \"Could not connect to Github\", e);\n }\n }\n\n if (errors.isEmpty()) {\n SecurityContext old = null;\n try {\n // We need to escalate privilege to add user defined endpoint to\n old = ACL.impersonate(ACL.SYSTEM);\n GitHubConfiguration config = GitHubConfiguration.get();\n String sanitizedUrl = discardQueryString(url);\n Endpoint endpoint = new Endpoint(sanitizedUrl, name);\n if (!config.addEndpoint(endpoint)) {\n errors.add(new ErrorMessage.Error(GithubServer.API_URL, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), GithubServer.API_URL + \" is already registered as '\" + endpoint.getName() + \"'\"));\n } else {\n return new GithubServer(endpoint, getLink());\n }\n }finally {\n //reset back to original privilege level\n if(old != null){\n SecurityContextHolder.setContext(old);\n }\n }\n }\n ErrorMessage message = new ErrorMessage(400, \"Failed to create GitHub server\");\n message.addAll(errors);\n throw new ServiceException.BadRequestException(message);\n }" +repo = "jenkinsci/blueocean-plugin" +url = "https://github.com/jenkinsci/blueocean-plugin.git" + +[[case]] +advisory = "GHSA-vc7g-4269-f7hw" +advisory_text = "Missing permission check in Blue Ocean Plugin\n\n### Updated 2020-09-16\nThis entry previously misidentified the problematic behavior. The HTTP request itself is legitimate, but only authorized users should be able to perform it.\n\n### Original Description\nBlue Ocean Plugin 1.23.2 and earlier does not perform permission checks in several HTTP endpoints implementing connection tests.\n\nThis allows attackers with Overall/Read permission to connect to an attacker-specified URL.\n\nBlue Ocean Plugin 1.23.3 requires Item/Create permission to perform these connection tests." +commit = "659a66aff0d0ad693eab9d2807985d591e102aab" +cwe = "CWE-862" +family = "access_control" +function = "create" +function_lines = [[44, 97]] +id = "jenkinsci-blueocean-plugin-e4ad2dadd845ec00" +language = "java" +method = "fix_site" +parent = "966da5a824c0e78767ba8b6a40be2ebfd8d8919f" +path = "blueocean-bitbucket-pipeline/src/main/java/io/jenkins/blueocean/blueocean_bitbucket_pipeline/server/BitbucketServerEndpointContainer.java" +post_fix = " public ScmServerEndpoint create(JSONObject request) {\n\n try {\n Jenkins.get().checkPermission(Item.CREATE);\n } catch (Exception e) {\n throw new ServiceException.ForbiddenException(\"User does not have permission to create repository\", e);\n }\n\n List errors = new LinkedList<>();\n\n // Validate name\n final String name = (String) request.get(ScmServerEndpoint.NAME);\n if(StringUtils.isBlank(name)){\n errors.add(new ErrorMessage.Error(ScmServerEndpoint.NAME, ErrorMessage.Error.ErrorCodes.MISSING.toString(), ScmServerEndpoint.NAME + \" is required\"));\n }\n\n String url = (String) request.get(ScmServerEndpoint.API_URL);\n final BitbucketEndpointConfiguration endpointConfiguration = BitbucketEndpointConfiguration.get();\n if(StringUtils.isBlank(url)){\n errors.add(new ErrorMessage.Error(ScmServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.MISSING.toString(), ScmServerEndpoint.API_URL + \" is required\"));\n }else {\n try {\n String version = BitbucketServerApi.getVersion(url);\n if (!BitbucketServerApi.isSupportedVersion(version)) {\n errors.add(new ErrorMessage.Error(BitbucketServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(),\n Messages.bbserver_version_validation_error(\n version, BitbucketServerApi.MINIMUM_SUPPORTED_VERSION)));\n } else {\n //validate presence of endpoint with same name\n url = BitbucketEndpointConfiguration.normalizeServerUrl(url);\n for (AbstractBitbucketEndpoint endpoint : endpointConfiguration.getEndpoints()) {\n if (url.equals(endpoint.getServerUrl())) {\n errors.add(new ErrorMessage.Error(ScmServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), ScmServerEndpoint.API_URL + \" already exists\"));\n break;\n }\n }\n }\n } catch (ServiceException e) {\n errors.add(new ErrorMessage.Error(BitbucketServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), StringUtils.isBlank(e.getMessage()) ? \"Invalid URL\" : e.getMessage()));\n }\n }\n\n if(!errors.isEmpty()){\n throw new ServiceException.BadRequestException(new ErrorMessage(400, \"Failed to create Bitbucket server endpoint\").addAll(errors));\n }\n final com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint endpoint = new com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint(name, url, false, null);\n SecurityContext old=null;\n try {\n // We need to escalate privilege to add user defined endpoint to\n old = ACL.impersonate(ACL.SYSTEM);\n endpointConfiguration.addEndpoint(endpoint);\n }finally {\n //reset back to original privilege level\n if(old != null){\n SecurityContextHolder.setContext(old);\n }\n }\n return new BitbucketServerEndpoint(endpoint, this);\n }\n\n @Override" +pre_fix = " public ScmServerEndpoint create(JSONObject request) {\n List errors = Lists.newLinkedList();\n\n // Validate name\n final String name = (String) request.get(ScmServerEndpoint.NAME);\n if(StringUtils.isBlank(name)){\n errors.add(new ErrorMessage.Error(ScmServerEndpoint.NAME, ErrorMessage.Error.ErrorCodes.MISSING.toString(), ScmServerEndpoint.NAME + \" is required\"));\n }\n\n String url = (String) request.get(ScmServerEndpoint.API_URL);\n final BitbucketEndpointConfiguration endpointConfiguration = BitbucketEndpointConfiguration.get();\n if(StringUtils.isBlank(url)){\n errors.add(new ErrorMessage.Error(ScmServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.MISSING.toString(), ScmServerEndpoint.API_URL + \" is required\"));\n }else {\n try {\n String version = BitbucketServerApi.getVersion(url);\n if (!BitbucketServerApi.isSupportedVersion(version)) {\n errors.add(new ErrorMessage.Error(BitbucketServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(),\n Messages.bbserver_version_validation_error(\n version, BitbucketServerApi.MINIMUM_SUPPORTED_VERSION)));\n } else {\n //validate presence of endpoint with same name\n url = BitbucketEndpointConfiguration.normalizeServerUrl(url);\n for (AbstractBitbucketEndpoint endpoint : endpointConfiguration.getEndpoints()) {\n if (url.equals(endpoint.getServerUrl())) {\n errors.add(new ErrorMessage.Error(ScmServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), ScmServerEndpoint.API_URL + \" already exists\"));\n break;\n }\n }\n }\n } catch (ServiceException e) {\n errors.add(new ErrorMessage.Error(BitbucketServerEndpoint.API_URL, ErrorMessage.Error.ErrorCodes.INVALID.toString(), StringUtils.isBlank(e.getMessage()) ? \"Invalid URL\" : e.getMessage()));\n }\n }\n\n if(!errors.isEmpty()){\n throw new ServiceException.BadRequestException(new ErrorMessage(400, \"Failed to create Bitbucket server endpoint\").addAll(errors));\n }\n final com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint endpoint = new com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint(name, url, false, null);\n SecurityContext old=null;\n try {\n // We need to escalate privilege to add user defined endpoint to\n old = ACL.impersonate(ACL.SYSTEM);\n endpointConfiguration.addEndpoint(endpoint);\n }finally {\n //reset back to original privilege level\n if(old != null){\n SecurityContextHolder.setContext(old);\n }\n }\n return new BitbucketServerEndpoint(endpoint, this);\n }\n\n @Override" +repo = "jenkinsci/blueocean-plugin" +url = "https://github.com/jenkinsci/blueocean-plugin.git" + +[[case]] +advisory = "GHSA-75fc-fv3p-xh82" +advisory_text = "Jenkins Compuware Source Code Download is missing authorization\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.12 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate hosts and ports of Compuware configurations and credentials IDs of credentials stored in Jenkins. Those credentials IDs can be used as part of an attack to capture the credentials using another vulnerability.\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.13 requires the appropriate permissions to enumerate hosts and ports of Compuware configurations and credentials IDs." +commit = "bf00665b13641351a9f67027bbe34609cc4f65e2" +cwe = "CWE-862" +family = "access_control" +function = "doFillConnectionIdItems" +function_lines = [[254, 276]] +id = "jenkinsci-compuware-scm-downloader-plugin-29636a1534a39217" +language = "java" +method = "fix_site" +parent = "115f057078baad506e2b34b74f4f0600f81990b3" +path = "src/main/java/com/compuware/jenkins/scm/PdsConfiguration.java" +post_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-scm-downloader-plugin" +url = "https://github.com/jenkinsci/compuware-scm-downloader-plugin.git" + +[[case]] +advisory = "GHSA-75fc-fv3p-xh82" +advisory_text = "Jenkins Compuware Source Code Download is missing authorization\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.12 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate hosts and ports of Compuware configurations and credentials IDs of credentials stored in Jenkins. Those credentials IDs can be used as part of an attack to capture the credentials using another vulnerability.\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.13 requires the appropriate permissions to enumerate hosts and ports of Compuware configurations and credentials IDs." +commit = "bf00665b13641351a9f67027bbe34609cc4f65e2" +cwe = "CWE-862" +family = "access_control" +function = "doFillConnectionIdItems" +function_lines = [[312, 334]] +id = "jenkinsci-compuware-scm-downloader-plugin-316557e9fdf67223" +language = "java" +method = "fix_site" +parent = "115f057078baad506e2b34b74f4f0600f81990b3" +path = "src/main/java/com/compuware/jenkins/scm/IspwContainerConfiguration.java" +post_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-scm-downloader-plugin" +url = "https://github.com/jenkinsci/compuware-scm-downloader-plugin.git" + +[[case]] +advisory = "GHSA-75fc-fv3p-xh82" +advisory_text = "Jenkins Compuware Source Code Download is missing authorization\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.12 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate hosts and ports of Compuware configurations and credentials IDs of credentials stored in Jenkins. Those credentials IDs can be used as part of an attack to capture the credentials using another vulnerability.\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.13 requires the appropriate permissions to enumerate hosts and ports of Compuware configurations and credentials IDs." +commit = "bf00665b13641351a9f67027bbe34609cc4f65e2" +cwe = "CWE-862" +family = "access_control" +function = "doFillCredentialsIdItems" +function_lines = [[107, 131]] +id = "jenkinsci-compuware-scm-downloader-plugin-4b64810cb01a07f5" +language = "java" +method = "fix_site" +parent = "115f057078baad506e2b34b74f4f0600f81990b3" +path = "src/main/java/com/compuware/jenkins/scm/AbstractConfiguration.java" +post_fix = "\t\tpublic ListBoxModel doFillCredentialsIdItems(@AncestorInPath Jenkins context, @QueryParameter String credentialsId,\n\t\t\t\t@AncestorInPath Item project) {\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\t\t\n\t\t\tList creds = CredentialsProvider.lookupCredentials(StandardCredentials.class, project, ACL.SYSTEM,\n\t\t\t\t\tCollections.emptyList());\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (StandardCredentials c : creds) {\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (credentialsId != null) {\n\t\t\t\t\tisSelected = credentialsId.matches(c.getId());\n\t\t\t\t}\n\n\t\t\t\tString description = Util.fixEmptyAndTrim(c.getDescription());\n\t\t\t\ttry {\n\t\t\t\t\tmodel.add(new Option(CpwrGlobalConfiguration.get().getCredentialsUser(c)\n\t\t\t\t\t\t\t+ (description != null ? (\" (\" + description + ')') : StringUtils.EMPTY), c.getId(), isSelected)); //$NON-NLS-1$\n\t\t\t\t} catch (AbortException e) {\n\t\t\t\t\tLOGGER.log(Level.WARNING, e.getMessage());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillCredentialsIdItems(@AncestorInPath Jenkins context, @QueryParameter String credentialsId,\n\t\t\t\t@AncestorInPath Item project) {\n\t\t\tList creds = CredentialsProvider.lookupCredentials(StandardCredentials.class, project, ACL.SYSTEM,\n\t\t\t\t\tCollections.emptyList());\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (StandardCredentials c : creds) {\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (credentialsId != null) {\n\t\t\t\t\tisSelected = credentialsId.matches(c.getId());\n\t\t\t\t}\n\n\t\t\t\tString description = Util.fixEmptyAndTrim(c.getDescription());\n\t\t\t\ttry {\n\t\t\t\t\tmodel.add(new Option(CpwrGlobalConfiguration.get().getCredentialsUser(c)\n\t\t\t\t\t\t\t+ (description != null ? (\" (\" + description + ')') : StringUtils.EMPTY), c.getId(), isSelected)); //$NON-NLS-1$\n\t\t\t\t} catch (AbortException e) {\n\t\t\t\t\tLOGGER.log(Level.WARNING, e.getMessage());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-scm-downloader-plugin" +url = "https://github.com/jenkinsci/compuware-scm-downloader-plugin.git" + +[[case]] +advisory = "GHSA-75fc-fv3p-xh82" +advisory_text = "Jenkins Compuware Source Code Download is missing authorization\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.12 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate hosts and ports of Compuware configurations and credentials IDs of credentials stored in Jenkins. Those credentials IDs can be used as part of an attack to capture the credentials using another vulnerability.\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.13 requires the appropriate permissions to enumerate hosts and ports of Compuware configurations and credentials IDs." +commit = "bf00665b13641351a9f67027bbe34609cc4f65e2" +cwe = "CWE-862" +family = "access_control" +function = "doFillConnectionIdItems" +function_lines = [[255, 277]] +id = "jenkinsci-compuware-scm-downloader-plugin-936a096a4a941ee5" +language = "java" +method = "fix_site" +parent = "115f057078baad506e2b34b74f4f0600f81990b3" +path = "src/main/java/com/compuware/jenkins/scm/EndevorConfiguration.java" +post_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-scm-downloader-plugin" +url = "https://github.com/jenkinsci/compuware-scm-downloader-plugin.git" + +[[case]] +advisory = "GHSA-75fc-fv3p-xh82" +advisory_text = "Jenkins Compuware Source Code Download is missing authorization\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.12 and earlier does not perform permission checks in several HTTP endpoints.\n\nThis allows attackers with Overall/Read permission to enumerate hosts and ports of Compuware configurations and credentials IDs of credentials stored in Jenkins. Those credentials IDs can be used as part of an attack to capture the credentials using another vulnerability.\n\nBMC Compuware Source Code Download for Endevor, PDS, and ISPW Plugin 2.0.13 requires the appropriate permissions to enumerate hosts and ports of Compuware configurations and credentials IDs." +commit = "bf00665b13641351a9f67027bbe34609cc4f65e2" +cwe = "CWE-862" +family = "access_control" +function = "doFillConnectionIdItems" +function_lines = [[416, 438]] +id = "jenkinsci-compuware-scm-downloader-plugin-c416a32628e63296" +language = "java" +method = "fix_site" +parent = "115f057078baad506e2b34b74f4f0600f81990b3" +path = "src/main/java/com/compuware/jenkins/scm/IspwConfiguration.java" +post_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-scm-downloader-plugin" +url = "https://github.com/jenkinsci/compuware-scm-downloader-plugin.git" + +[[case]] +advisory = "GHSA-x5gv-5rqv-654m" +advisory_text = "Jenkins Compuware Topaz for Total Test Plugin allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins\n\nJenkins Compuware Topaz for Total Test Plugin 2.4.8 and earlier does not perform permission checks in several HTTP endpoints, allowing attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "0ba4274d545eac39e3db48b5dfb4512db3242946" +cwe = "CWE-862" +family = "access_control" +function = "doFillCredentialsIdItems" +function_lines = [[857, 889]] +id = "jenkinsci-compuware-topaz-for-total-test-plugin-0fcc9e440100be20" +language = "java" +method = "fix_site" +parent = "5fca6eb21599f8f27323dfa17a6e44f8176ca551" +path = "src/main/java/com/compuware/jenkins/totaltest/TotalTestBuilder.java" +post_fix = "\t\tpublic ListBoxModel doFillCredentialsIdItems(@AncestorInPath final Jenkins context, @QueryParameter final String credentialsId, @AncestorInPath final Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\t\t\t\n\t\t\tList creds = CredentialsProvider\n\t\t\t\t\t.lookupCredentials(StandardUsernamePasswordCredentials.class, project, ACL.SYSTEM,\n\t\t\t\t\t\t\tCollections. emptyList());\n\n\t\t\tStandardListBoxModel model = new StandardListBoxModel();\n\n\t\t\tmodel.add(new Option(EMPTY_STRING, EMPTY_STRING, false));\n\n\t\t\tfor (StandardUsernamePasswordCredentials c : creds)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\n\t\t\t\tif (credentialsId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = credentialsId.matches(c.getId());\n\t\t\t\t}\n\n\t\t\t\tString description = Util.fixEmptyAndTrim(c.getDescription());\n\t\t\t\tmodel.add(new Option(c.getUsername()\n\t\t\t\t\t\t+ (description != null ? \" (\" + description + \")\" : EMPTY_STRING), c.getId(), isSelected)); //$NON-NLS-1$ //$NON-NLS-2$\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}\n\t\t\n\t\t/*\n\t\t * (non-Javadoc)\n\t\t * @see hudson.tasks.BuildStepDescriptor#isApplicable(java.lang.Class)\n\t\t */\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\t@Override" +pre_fix = "\t\tpublic ListBoxModel doFillCredentialsIdItems(@AncestorInPath final Jenkins context, @QueryParameter final String credentialsId, @AncestorInPath final Item project)\n\t\t{\n\t\t\tList creds = CredentialsProvider\n\t\t\t\t\t.lookupCredentials(StandardUsernamePasswordCredentials.class, project, ACL.SYSTEM,\n\t\t\t\t\t\t\tCollections. emptyList());\n\n\t\t\tStandardListBoxModel model = new StandardListBoxModel();\n\n\t\t\tmodel.add(new Option(EMPTY_STRING, EMPTY_STRING, false));\n\n\t\t\tfor (StandardUsernamePasswordCredentials c : creds)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\n\t\t\t\tif (credentialsId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = credentialsId.matches(c.getId());\n\t\t\t\t}\n\n\t\t\t\tString description = Util.fixEmptyAndTrim(c.getDescription());\n\t\t\t\tmodel.add(new Option(c.getUsername()\n\t\t\t\t\t\t+ (description != null ? \" (\" + description + \")\" : EMPTY_STRING), c.getId(), isSelected)); //$NON-NLS-1$ //$NON-NLS-2$\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}\n\t\t\n\t\t/*\n\t\t * (non-Javadoc)\n\t\t * @see hudson.tasks.BuildStepDescriptor#isApplicable(java.lang.Class)\n\t\t */\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\t@Override" +repo = "jenkinsci/compuware-topaz-for-total-test-plugin" +url = "https://github.com/jenkinsci/compuware-topaz-for-total-test-plugin.git" + +[[case]] +advisory = "GHSA-x5gv-5rqv-654m" +advisory_text = "Jenkins Compuware Topaz for Total Test Plugin allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins\n\nJenkins Compuware Topaz for Total Test Plugin 2.4.8 and earlier does not perform permission checks in several HTTP endpoints, allowing attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "0ba4274d545eac39e3db48b5dfb4512db3242946" +cwe = "CWE-862" +family = "access_control" +function = "doFillConnectionIdItems" +function_lines = [[1534, 1556]] +id = "jenkinsci-compuware-topaz-for-total-test-plugin-31007615cf224711" +language = "java" +method = "fix_site" +parent = "5fca6eb21599f8f27323dfa17a6e44f8176ca551" +path = "src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java" +post_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\t\t\t\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection hostConnection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(hostConnection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(hostConnection.getDescription() + \" [\" + hostConnection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\thostConnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection hostConnection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(hostConnection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(hostConnection.getDescription() + \" [\" + hostConnection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\thostConnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-topaz-for-total-test-plugin" +url = "https://github.com/jenkinsci/compuware-topaz-for-total-test-plugin.git" + +[[case]] +advisory = "GHSA-x5gv-5rqv-654m" +advisory_text = "Jenkins Compuware Topaz for Total Test Plugin allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins\n\nJenkins Compuware Topaz for Total Test Plugin 2.4.8 and earlier does not perform permission checks in several HTTP endpoints, allowing attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "0ba4274d545eac39e3db48b5dfb4512db3242946" +cwe = "CWE-862" +family = "access_control" +function = "doFillConnectionIdItems" +function_lines = [[798, 820]] +id = "jenkinsci-compuware-topaz-for-total-test-plugin-3b2dc3167c986714" +language = "java" +method = "fix_site" +parent = "5fca6eb21599f8f27323dfa17a6e44f8176ca551" +path = "src/main/java/com/compuware/jenkins/totaltest/TotalTestBuilder.java" +post_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\t\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\t\t\t\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillConnectionIdItems(@AncestorInPath Jenkins context, @QueryParameter String connectionId,\n\t\t\t\t@AncestorInPath Item project)\n\t\t{\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(StringUtils.EMPTY, StringUtils.EMPTY, false));\n\n\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\t\t\t\tif (connectionId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = connectionId.matches(connection.getConnectionId());\n\t\t\t\t}\n\n\t\t\t\tmodel.add(new Option(connection.getDescription() + \" [\" + connection.getHostPort() + ']', //$NON-NLS-1$\n\t\t\t\t\t\tconnection.getConnectionId(), isSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-topaz-for-total-test-plugin" +url = "https://github.com/jenkinsci/compuware-topaz-for-total-test-plugin.git" + +[[case]] +advisory = "GHSA-x5gv-5rqv-654m" +advisory_text = "Jenkins Compuware Topaz for Total Test Plugin allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins\n\nJenkins Compuware Topaz for Total Test Plugin 2.4.8 and earlier does not perform permission checks in several HTTP endpoints, allowing attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "0ba4274d545eac39e3db48b5dfb4512db3242946" +cwe = "CWE-862" +family = "access_control" +function = "doFillCredentialsIdItems" +function_lines = [[1644, 1670]] +id = "jenkinsci-compuware-topaz-for-total-test-plugin-8659f27b971d364f" +language = "java" +method = "fix_site" +parent = "5fca6eb21599f8f27323dfa17a6e44f8176ca551" +path = "src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java" +post_fix = "\t\tpublic ListBoxModel doFillCredentialsIdItems(@AncestorInPath final Jenkins context, //NOSONAR\n\t\t\t\t@QueryParameter final String credentialsId, @AncestorInPath final Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\t\t\tList creds = CredentialsProvider.lookupCredentials(\n\t\t\t\t\tStandardUsernamePasswordCredentials.class, project, ACL.SYSTEM,\n\t\t\t\t\tCollections. emptyList());\n\n\t\t\tStandardListBoxModel model = new StandardListBoxModel();\n\n\t\t\tmodel.add(new Option(\"\", \"\", false)); //$NON-NLS-1$ //$NON-NLS-2$\n\n\t\t\tfor (StandardUsernamePasswordCredentials c : creds)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\n\t\t\t\tif (credentialsId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = credentialsId.matches(c.getId());\n\t\t\t\t}\n\n\t\t\t\tString description = Util.fixEmptyAndTrim(c.getDescription());\n\t\t\t\tmodel.add(new Option(c.getUsername() + (description != null ? \" (\" + description + \")\" : \"\"), c.getId(), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$\n\t\t\t\t\t\tisSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +pre_fix = "\t\tpublic ListBoxModel doFillCredentialsIdItems(@AncestorInPath final Jenkins context, //NOSONAR\n\t\t\t\t@QueryParameter final String credentialsId, @AncestorInPath final Item project)\n\t\t{\n\t\t\tList creds = CredentialsProvider.lookupCredentials(\n\t\t\t\t\tStandardUsernamePasswordCredentials.class, project, ACL.SYSTEM,\n\t\t\t\t\tCollections. emptyList());\n\n\t\t\tStandardListBoxModel model = new StandardListBoxModel();\n\n\t\t\tmodel.add(new Option(\"\", \"\", false)); //$NON-NLS-1$ //$NON-NLS-2$\n\n\t\t\tfor (StandardUsernamePasswordCredentials c : creds)\n\t\t\t{\n\t\t\t\tboolean isSelected = false;\n\n\t\t\t\tif (credentialsId != null)\n\t\t\t\t{\n\t\t\t\t\tisSelected = credentialsId.matches(c.getId());\n\t\t\t\t}\n\n\t\t\t\tString description = Util.fixEmptyAndTrim(c.getDescription());\n\t\t\t\tmodel.add(new Option(c.getUsername() + (description != null ? \" (\" + description + \")\" : \"\"), c.getId(), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$\n\t\t\t\t\t\tisSelected));\n\t\t\t}\n\n\t\t\treturn model;\n\t\t}" +repo = "jenkinsci/compuware-topaz-for-total-test-plugin" +url = "https://github.com/jenkinsci/compuware-topaz-for-total-test-plugin.git" + +[[case]] +advisory = "GHSA-x5gv-5rqv-654m" +advisory_text = "Jenkins Compuware Topaz for Total Test Plugin allows attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins\n\nJenkins Compuware Topaz for Total Test Plugin 2.4.8 and earlier does not perform permission checks in several HTTP endpoints, allowing attackers with Overall/Read permission to enumerate credentials IDs of credentials stored in Jenkins." +commit = "0ba4274d545eac39e3db48b5dfb4512db3242946" +cwe = "CWE-862" +family = "access_control" +function = "doFillServerUrlItems" +function_lines = [[1681, 1773]] +id = "jenkinsci-compuware-topaz-for-total-test-plugin-b0ca3df515237e75" +language = "java" +method = "fix_site" +parent = "5fca6eb21599f8f27323dfa17a6e44f8176ca551" +path = "src/main/java/com/compuware/jenkins/totaltest/TotalTestCTBuilder.java" +post_fix = "\t\tpublic ListBoxModel doFillServerUrlItems(@QueryParameter String serverUrl,@AncestorInPath final Item project)\n\t\t{\n\t\t\tif (project == null) {\n\t\t\t\tJenkins.get().checkPermission(Jenkins.ADMINISTER);\n\t\t\t} else {\n\t\t\t\tproject.checkPermission(Item.CONFIGURE);\n\t\t\t}\n\t\t\t\n\t\t\tListBoxModel model = new ListBoxModel();\n\t\t\tmodel.add(new Option(\"\", \"\", false)); //$NON-NLS-1$ //$NON-NLS-2$\n\t\t\tCpwrGlobalConfiguration globalConfig = CpwrGlobalConfiguration.get();\n\t\t\tif (globalConfig != null)\n\t\t\t{\n\t\t\t\tHostConnection[] hostConnections = globalConfig.getHostConnections();\n\n\t\t\t\tfor (HostConnection connection : hostConnections)\n\t\t\t\t{\n\t\t\t\t\tString cesServerURL = connection.getCesUrl();\n\t\t\t\t\tif (cesServerURL != null && !cesServerURL.isEmpty())\n\t\t\t\t\t{\n\t\t\t\t\t\tboolean isSelected = false;\n\t\t\t\t\t\tif (serverUrl != null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tisSelected = serverUrl.equalsIgnoreCase(cesServerURL);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tString cesValue = cesServerURL;\n\t\t\t\t\t\tOption opt = new Option(cesValue, cesServerURL, isSelected);\n\t\t\t\t\t\tboolean exists = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tListIterator