GHSA-5JP2-VWRJ-99RF
Vulnerability from github – Published: 2022-10-19 20:26 – Updated: 2025-04-16 16:08Impact
For some Post/Put Concourse endpoint containing :team_name in the URL, a Concourse user can send a request with body including :team_name=team2 to bypass team scope check to gain access to certain resources belong to any other team. The user only needs a valid user session and belongs to team2.
Exploitable endpoints:
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/builds/:build_name", Method: "POST", Name: RerunJobBuild},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/pause", Method: "PUT", Name: PauseJob},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/unpause", Method: "PUT", Name: UnpauseJob},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/schedule", Method: "PUT", Name: ScheduleJob},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/pause", Method: "PUT", Name: PausePipeline},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/unpause", Method: "PUT", Name: UnpausePipeline},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/expose", Method: "PUT", Name: ExposePipeline},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/hide", Method: "PUT", Name: HidePipeline},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/rename", Method: "PUT", Name: RenamePipeline},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/archive", Method: "PUT", Name: ArchivePipeline},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/versions/:resource_config_version_id/enable", Method: "PUT", Name: EnableResourceVersion},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/versions/:resource_config_version_id/disable", Method: "PUT", Name: DisableResourceVersion},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/versions/:resource_config_version_id/pin", Method: "PUT", Name: PinResourceVersion},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/unpin", Method: "PUT", Name: UnpinResource},
{Path: "/api/v1/teams/:team_name/artifacts", Method: "POST", Name: CreateArtifact},
Steps to reproduce
- Set up a Concourse deployment with team 1 (with pipeline 1) and team 2. User is in team 2 but not team 1.
- Login as user to team 2.
fly -t ci login -n team2 -u user -p password
- Try pausing pipeline 1 in team 1 using fly. Verify the command output is
pipeline 'pipeline1' not found.
fly -t ci pause-pipeline -p pipeline1
- Send a customized request through
fly curlcommand intend to pause pipeline 1 again.
fly -t ci curl /api/v1/teams/team1/pipelines/pipeline1/pause -- -X PUT -d ":team_name=team2" -H "Content-type: application/x-www-form-urlencoded"
- pipeline 1 in team 1 will be paused.
In step 4, the parameter pollution would allow an user from any team to pause a pipeline that belongs to other team.
Patches
Concourse v6.7.9 and v7.8.3 were both released with a fix on October 12, 2022.
Instead of using FormValue to parse team_name in the request, where allows body parameters to take precedence over URL query string values, both patch versions are now using URL.Query().Get() over multiple scope handlers to prevent the parameter pollution.
Workarounds
No known workarounds for existing versions.
References
- https://github.com/concourse/concourse/pull/8566: PR with the fix
For more information
If you have any questions or comments about this advisory, you may reach us privately at security@concourse-ci.org.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/concourse/concourse"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.7.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/concourse/concourse"
},
"ranges": [
{
"events": [
{
"introduced": "7.0.0"
},
{
"fixed": "7.8.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2022-31683"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2022-10-19T20:26:05Z",
"nvd_published_at": "2022-12-19T16:15:00Z",
"severity": "MODERATE"
},
"details": "### Impact\nFor some Post/Put Concourse endpoint containing `:team_name` in the URL, a Concourse user can send a request with body including `:team_name=team2` to bypass team scope check to gain access to certain resources belong to any other team. The user only needs a valid user session and belongs to team2.\n\nExploitable endpoints:\n```\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/builds/:build_name\", Method: \"POST\", Name: RerunJobBuild},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/pause\", Method: \"PUT\", Name: PauseJob},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/unpause\", Method: \"PUT\", Name: UnpauseJob},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name/schedule\", Method: \"PUT\", Name: ScheduleJob},\n\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/pause\", Method: \"PUT\", Name: PausePipeline},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/unpause\", Method: \"PUT\", Name: UnpausePipeline},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/expose\", Method: \"PUT\", Name: ExposePipeline},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/hide\", Method: \"PUT\", Name: HidePipeline},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/rename\", Method: \"PUT\", Name: RenamePipeline},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/archive\", Method: \"PUT\", Name: ArchivePipeline},\n\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/versions/:resource_config_version_id/enable\", Method: \"PUT\", Name: EnableResourceVersion},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/versions/:resource_config_version_id/disable\", Method: \"PUT\", Name: DisableResourceVersion},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/versions/:resource_config_version_id/pin\", Method: \"PUT\", Name: PinResourceVersion},\n{Path: \"/api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/unpin\", Method: \"PUT\", Name: UnpinResource},\n\t\n{Path: \"/api/v1/teams/:team_name/artifacts\", Method: \"POST\", Name: CreateArtifact},\n```\n\n### Steps to reproduce\n\n1. Set up a Concourse deployment with team 1 (with pipeline 1) and team 2. User is in team 2 but not team 1.\n2. Login as user to team 2.\n```\nfly -t ci login -n team2 -u user -p password\n```\n3. Try pausing pipeline 1 in team 1 using fly. Verify the command output is `pipeline \u0027pipeline1\u0027 not found`.\n```\nfly -t ci pause-pipeline -p pipeline1\n```\n\n\n4. Send a customized request through `fly curl` command intend to pause pipeline 1 again. \n```\nfly -t ci curl /api/v1/teams/team1/pipelines/pipeline1/pause -- -X PUT -d \":team_name=team2\" -H \"Content-type: application/x-www-form-urlencoded\"\n```\n5. pipeline 1 in team 1 will be paused.\n\nIn step 4, the parameter pollution would allow an user from any team to pause a pipeline that belongs to other team.\n\n### Patches\nConcourse [v6.7.9](https://github.com/concourse/concourse/releases/tag/v6.7.9) and [v7.8.3](https://github.com/concourse/concourse/releases/tag/v7.8.3) were both released with a fix on October 12, 2022.\n\nInstead of using [`FormValue`](https://pkg.go.dev/net/http#Request.FormValue) to parse team_name in the request, where allows body parameters to take precedence over URL query string values, both patch versions are now using `URL.Query().Get()` over multiple scope handlers to prevent the parameter pollution.\n\n### Workarounds\nNo known workarounds for existing versions.\n\n### References\n * https://github.com/concourse/concourse/pull/8566: PR with the fix\n\n### For more information\nIf you have any questions or comments about this advisory, you may reach us privately at [security@concourse-ci.org](mailto:security@concourse-ci.org).",
"id": "GHSA-5jp2-vwrj-99rf",
"modified": "2025-04-16T16:08:47Z",
"published": "2022-10-19T20:26:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/security/advisories/GHSA-5jp2-vwrj-99rf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-31683"
},
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/pull/8566"
},
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/pull/8580"
},
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/commit/57e06711b0d861775a5a6bd078a34abeb0e2638e"
},
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/commit/ba885834d9bcbb9d1ccb9964faa7af0e78a72205"
},
{
"type": "PACKAGE",
"url": "https://github.com/concourse/concourse"
},
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/releases/tag/v6.7.9"
},
{
"type": "WEB",
"url": "https://github.com/concourse/concourse/releases/tag/v7.8.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Team scope authorization bypass when Post/Put request with :team_name in body, allows HTTP parameter pollution "
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.