Add proper authorization to vulnerability details fields
What does this MR do and why?
This MR adds proper authorization to fields required to fetch vulnerability details
The GraphQL query used to do it follows:
fragment Url on VulnerabilityDetailUrl {
type: __typename
name
href
}
fragment Diff on VulnerabilityDetailDiff {
type: __typename
name
before
after
}
fragment Code on VulnerabilityDetailCode {
type: __typename
name
value
}
fragment FileLocation on VulnerabilityDetailFileLocation {
type: __typename
name
fileName
lineStart
lineEnd
}
fragment ModuleLocation on VulnerabilityDetailModuleLocation {
type: __typename
name
moduleName
offset
}
fragment Commit on VulnerabilityDetailCommit {
type: __typename
name
value
}
fragment Text on VulnerabilityDetailText {
type: __typename
name
value
}
fragment Markdown on VulnerabilityDetailMarkdown {
type: __typename
name
value
}
fragment Boolean on VulnerabilityDetailBoolean {
type: __typename
name
value
}
fragment Int on VulnerabilityDetailInt {
type: __typename
name
value
}
fragment NonNestedReportTypes on VulnerabilityDetail {
...FileLocation
...Url
...Diff
...Code
...Commit
...Markdown
...Text
...Int
...Boolean
...ModuleLocation
}
fragment ListFields on VulnerabilityDetailList {
type: __typename
name
}
fragment List on VulnerabilityDetailList {
...ListFields
items {
...NonNestedReportTypes
... on VulnerabilityDetailList {
...ListFields
items {
...NonNestedReportTypes
}
}
}
}
fragment NamedList on VulnerabilityDetailNamedList {
type: __typename
name
items {
name
fieldName
value {
...NonNestedReportTypes
...Table
... on VulnerabilityDetailList {
...ListFields
items {
...NonNestedReportTypes
}
}
}
}
}
fragment CodeFlowNode on VulnerabilityDetailCodeFlowNode {
type: __typename
nodeType
fileLocation {
...FileLocation
}
}
fragment CodeFlows on VulnerabilityDetailCodeFlows {
type: __typename
name
items {
... {
...CodeFlowNode
}
}
}
fragment TableFields on VulnerabilityDetailTable {
type: __typename
name
headers {
...NonNestedReportTypes
}
rows {
row {
...NonNestedReportTypes
}
}
}
fragment Table on VulnerabilityDetailTable {
type: __typename
name
headers {
...NonNestedReportTypes
}
rows {
row {
...NonNestedReportTypes
...TableFields
}
}
}
{
vulnerability(id: "gid://gitlab/Vulnerability/567") {
id
title
state
description
reachability
cveEnrichment {
cve
epssScore
isKnownExploit
}
detectedAt
dismissedAt
initialDetectedPipeline {
id
name
createdAt
}
location {
__typename
... on VulnerabilityLocationClusterImageScanning {
image
kubernetesResource {
agent {
id
name
webPath
}
}
}
... on VulnerabilityLocationContainerScanning {
image
containerRepositoryUrl
}
... on VulnerabilityLocationCoverageFuzzing {
blobPath
crashAddress
crashType
endLine
file
stacktraceSnippet
startLine
vulnerableClass
vulnerableMethod
}
... on VulnerabilityLocationDast {
path
}
... on VulnerabilityLocationDependencyScanning {
blobPath
file
}
... on VulnerabilityLocationGeneric {
description
}
... on VulnerabilityLocationSast {
blobPath
file
startLine
}
... on VulnerabilityLocationSecretDetection {
blobPath
file
startLine
}
}
details {
__typename
...NonNestedReportTypes
...List
...Table
...NamedList
...CodeFlows
...NonNestedReportTypes
}
}
}
How this beast was created? It was inspired by [relevant part] of security findings report
References
#554679+
Screenshots or screen recordings
N/A
How to set up and validate locally
- Seed the vulnerabilities by running
bin/rake 'gitlab:seed:vulnerabilities[gitlab-org/gitlab-shell]' - In the rails console of the GDK, create a new OAuth access token with
ai_workflowsscope and get the last id of seeded vulnerability.
[1] pry(main)> application = Doorkeeper::Application.create!(
name: "AI Workflows App",
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
scopes: "ai_workflows",
owner: User.find_by_username("root")
=> #<Doorkeeper::Application:0x000000031eb34cc0
[2] pry(main)> Doorkeeper::AccessToken.create!(
application_id: application.id,
resource_owner_id: application.owner.id,
scopes: "ai_workflows",
expires_in: 1.year.to_i,
=> "30bad7653d06a57435358cf774cd094df403ff981b38d9de4e262b5ff0c2ab51"
[3] pry(main)> Vulnerability.last.id
=> 570
- Send a request with the new token in Authorization header to a relevant endpoint. Do not forget to replace 999 at the start of
--data-rawsection of command line with number you've retrieved on previous step (570 in my example)
% curl 'http://gdk.test:3000/api/graphql' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer 30bad7653d06a57435358cf774cd094df403ff981b38d9de4e262b5ff0c2ab51' \
--data-raw $'{"variables":{"vulnerabilityId":"gid://gitlab/Vulnerability/999"}, "operationName":"VulnerabilityDetails","query":"fragment Url on VulnerabilityDetailUrl {\\n type: __typename\\n name\\n href\\n}\\n\\nfragment Diff on VulnerabilityDetailDiff {\\n type: __typename\\n name\\n before\\n after\\n}\\n\\nfragment Code on VulnerabilityDetailCode {\\n type: __typename\\n name\\n value\\n}\\n\\nfragment FileLocation on VulnerabilityDetailFileLocation {\\n type: __typename\\n name\\n fileName\\n lineStart\\n lineEnd\\n}\\n\\nfragment ModuleLocation on VulnerabilityDetailModuleLocation {\\n type: __typename\\n name\\n moduleName\\n offset\\n}\\n\\nfragment Commit on VulnerabilityDetailCommit {\\n type: __typename\\n name\\n value\\n}\\n\\nfragment Text on VulnerabilityDetailText {\\n type: __typename\\n name\\n value\\n}\\n\\nfragment Markdown on VulnerabilityDetailMarkdown {\\n type: __typename\\n name\\n value\\n}\\n\\nfragment Boolean on VulnerabilityDetailBoolean {\\n type: __typename\\n name\\n value\\n}\\n\\nfragment Int on VulnerabilityDetailInt {\\n type: __typename\\n name\\n value\\n}\\n\\nfragment NonNestedReportTypes on VulnerabilityDetail {\\n ...FileLocation\\n ...Url\\n ...Diff\\n ...Code\\n ...Commit\\n ...Markdown\\n ...Text\\n ...Int\\n ...Boolean\\n ...ModuleLocation\\n}\\n\\nfragment ListFields on VulnerabilityDetailList {\\n type: __typename\\n name\\n}\\n\\nfragment List on VulnerabilityDetailList {\\n ...ListFields\\n items {\\n ...NonNestedReportTypes\\n ... on VulnerabilityDetailList {\\n ...ListFields\\n items {\\n ...NonNestedReportTypes\\n }\\n }\\n }\\n}\\n\\nfragment NamedList on VulnerabilityDetailNamedList {\\n type: __typename\\n name\\n items {\\n name\\n fieldName\\n value {\\n ...NonNestedReportTypes\\n ...Table\\n ... on VulnerabilityDetailList {\\n ...ListFields\\n items {\\n ...NonNestedReportTypes\\n }\\n }\\n }\\n }\\n}\\n\\nfragment CodeFlowNode on VulnerabilityDetailCodeFlowNode {\\n type: __typename\\n nodeType\\n fileLocation {\\n ...FileLocation\\n }\\n}\\n\\nfragment CodeFlows on VulnerabilityDetailCodeFlows {\\n type: __typename\\n name\\n items {\\n ... {\\n ...CodeFlowNode\\n }\\n }\\n}\\n\\nfragment TableFields on VulnerabilityDetailTable {\\n type: __typename\\n name\\n headers {\\n ...NonNestedReportTypes\\n }\\n rows {\\n row {\\n ...NonNestedReportTypes\\n }\\n }\\n}\\n\\nfragment Table on VulnerabilityDetailTable {\\n type: __typename\\n name\\n headers {\\n ...NonNestedReportTypes\\n }\\n rows {\\n row {\\n ...NonNestedReportTypes\\n ...TableFields\\n }\\n }\\n}\\n\\nquery VulnerabilityDetails($vulnerabilityId: VulnerabilityID\u0021) {\\n vulnerability(id: $vulnerabilityId) {\\n id\\n title\\n state\\n description\\n reachability\\n cveEnrichment {\\n cve\\n epssScore\\n isKnownExploit\\n }\\n detectedAt\\n dismissedAt\\n initialDetectedPipeline {\\n id\\n name\\n createdAt\\n }\\n location {\\n __typename\\n ... on VulnerabilityLocationClusterImageScanning {\\n image\\n kubernetesResource {\\n agent {\\n id\\n name\\n webPath\\n }\\n }\\n }\\n ... on VulnerabilityLocationContainerScanning {\\n image\\n containerRepositoryUrl\\n }\\n ... on VulnerabilityLocationCoverageFuzzing {\\n blobPath\\n crashAddress\\n crashType\\n endLine\\n file\\n stacktraceSnippet\\n startLine\\n vulnerableClass\\n vulnerableMethod\\n }\\n ... on VulnerabilityLocationDast {\\n path\\n }\\n ... on VulnerabilityLocationDependencyScanning {\\n blobPath\\n file\\n }\\n ... on VulnerabilityLocationGeneric {\\n description\\n }\\n ... on VulnerabilityLocationSast {\\n blobPath\\n file\\n startLine\\n }\\n ... on VulnerabilityLocationSecretDetection {\\n blobPath\\n file\\n startLine\\n }\\n }\\n details {\\n __typename\\n ...NonNestedReportTypes\\n ...List\\n ...Table\\n ...NamedList\\n ...CodeFlows\\n ...NonNestedReportTypes\\n }\\n }\\n}"}' | jq
Observe the output:
{
"data": {
"vulnerability": {
"id": "gid://gitlab/Vulnerability/570",
"title": "Cypher with no integrity",
"state": "DISMISSED",
"description": "Description of Cypher with no integrity",
"reachability": null,
"cveEnrichment": null,
"detectedAt": "2025-07-25T16:20:23Z",
"dismissedAt": "2025-07-25T16:20:23Z",
"initialDetectedPipeline": {
"id": "gid://gitlab/Ci::Pipeline/594",
"name": null,
"createdAt": "2025-07-25T16:20:23Z"
},
"location": {
"__typename": "VulnerabilityLocationClusterImageScanning",
"image": null,
"kubernetesResource": null
},
"details": [
{
"__typename": "VulnerabilityDetailUrl",
"type": "VulnerabilityDetailUrl",
"name": "URL",
"href": "http://site.com"
}
]
}
}
}
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Edited by Illya Klymov