GCVE-1988-2026-0521
Vulnerability from gna-1988 – Published: 2026-11-02 09:31 – Updated: 2026-11-02 09:31
VLAI
EPSS
VEX
Title
harness Gitspace hardcoded password for every user account
Summary
# harness Gitspace hardcoded password for every user account
**Author:** Khashayar Fereidani
**Disclosure Date:** 2026-09-24
**Advisory:** https://fereidani.com/harness-gitspace-hardcoded-password-for-every-user-account
**Contact:** https://fereidani.com/contact
## Description
Gitspaces are Harness's hosted development environments: a container with
the user's source tree, running an SSH server and an IDE, with its ports
published on the host machine. Access is supposed to be controlled by a
secret the user configures. In practice the password of the Linux account
inside every Gitspace container is the same public constant,
`app/gitspace/secret/password_resolver.go:26`:
```go
const defaultPassword = "Harness@123"
func (p *PasswordResolver) Resolve(_ context.Context, _
ResolutionContext) (ResolvedSecret, error) {
return ResolvedSecret{
SecretValue: defaultPassword,
}, nil
}
```
`Resolve` discards the entire `ResolutionContext`, parameter by parameter.
The caller does pass the configured reference: `ResolveSecret` builds the
context with `SecretRef: *config.GitspaceInstance.AccessKeyRef`
(`app/gitspace/orchestrator/utils/secret.go:46`), but the resolver never
reads it, so the user's choice of secret is ignored and the value cannot be
rotated per instance. The wire set registers exactly this one resolver
(`app/gitspace/secret/wire.go:20`), so every password-type resolution in the
product returns the constant.
The resolved value becomes the account password inside the container. On
resume, the orchestrator stores it
(`app/gitspace/orchestrator/orchestrator_resume.go:50`) and the user setup
script applies it (`manage_user.sh` under
`app/gitspace/orchestrator/utils/script_templates/`, line 49):
```sh
elif [ "user_credentials" = "$accessType" ] ; then
echo "$username:$accessKey" | chpasswd
```
The constant ships in the public repository, so it is known to anyone who
has read the source, and it is identical in every deployment, every release
image and every Gitspace instance. The `ssh_key` branch of the same script
writes the resolved value into `authorized_keys`
(`manage_user.sh:43-46`); since that value is also the constant, that access
type simply does not work, which is further proof that the configured
reference is never honored.
## Reproduction
The resolver can be exercised directly. This in-package test asks it to
resolve a configured secret reference:
```go
package secret
import (
"context"
"testing"
)
func TestPocHardcodedPassword(t *testing.T) {
resolved, err := (&PasswordResolver{}).Resolve(context.Background(),
ResolutionContext{
UserIdentifier: "victim",
GitspaceIdentifier: "gs-1",
SecretRef: "my-configured-secret-ref",
SpaceIdentifier: "space1",
})
if err != nil {
t.Fatal(err)
}
t.Logf("Resolve(SecretRef=%q) = %q", "my-configured-secret-ref",
resolved.SecretValue)
if resolved.SecretValue != "Harness@123" {
t.Fatalf("expected the shipped constant, got %q", resolved.SecretValue)
}
}
```
Observed output on main at commit 912a1f3:
```text
--- PASS: TestPocHardcodedPassword (0.00s)
poc_password_test.go:18:
Resolve(SecretRef="my-configured-secret-ref") = "Harness@123"
```
With a running deployment the account is then usable directly. Gitspace
ports are published as host port bindings
(`app/gitspace/orchestrator/container/devcontainer_container_utils.go:281`),
and the account name is the Gitspace owner's identifier
(`config.GitspaceUser.Identifier` in the same plumbing), so anyone who can
reach the published SSH port logs in with the public constant:
```sh
ssh <owner-identifier>@<gitspace-host> -p <published-port>
# password: Harness@123
```
## Impact
Use of a hard-coded password (CWE-798, CWE-259). An attacker who can reach
a Gitspace's published SSH or IDE endpoint gets the owner's full
environment: the source tree, any git credentials and tokens present in the
container, and the network position of the development sandbox. There is no
per-instance secret to stop them, because the value is universal, public in
the source repository, and cannot be changed through configuration since
the resolver ignores the reference. Anyone who has ever read the source, or
any attacker who obtained the constant from any other deployment, holds a
valid password for every Gitspace account in every Harness open source
installation.
## Solution
Make the resolver earn its name. Two workable directions, in order of
preference:
- Honor the configured reference. The codebase already defines the seam:
`PlatformSecret.FetchSecret(ctx, secretRef, spacePath)`
(`app/gitspace/platformsecret/platformsecret.go:23`). Its only
implementation currently ignores both the reference and the space path and
returns its input masked (`gitnessplatformsecret.go:31`), so wire it to
the existing secret service and have `PasswordResolver.Resolve` read
`ResolutionContext.SecretRef` through it. Users can then set and rotate
the real password as a proper secret.
- Or drop shared passwords entirely: generate a random per-instance
password with `crypto/rand` at Gitspace start and hand it to the owner
through the control plane (the API or the IDE session), never storing a
constant in the repository.
Either way, a resolver that cannot produce a real secret should return an
error, not a known constant. Until a fix lands, treat every published
Gitspace port as a pre-authenticated login for the owner account: keep the
ports off public networks (firewall, VPN or bind them to loopback with an
authenticated tunnel in front), because no configuration change inside the
product can change the password.
## Timeline
- 2026-09-24: Reported publicly as harness/harness#3725, found while
scanning popular repositories with my static analyzer. The project's
earlier security reports had gone unanswered; the current main branch
(912a1f3) is affected.
## References
- [harness/harness#3725 - hardcoded password Harness@123 for every
gitspace user account](https://github.com/harness/harness/issues/3725)
- [harness/harness -
app/gitspace/secret/password_resolver.go](https://github.com/harness/harness/blob/main/app/gitspace/secret/password_resolver.go)
- [harness/harness -
app/gitspace/orchestrator/utils/script_templates/manage_user.sh](https://github.com/harness/harness/blob/main/app/gitspace/orchestrator/utils/script_templates/manage_user.sh)
- [harness/harness -
app/gitspace/platformsecret/platformsecret.go](https://github.com/harness/harness/blob/main/app/gitspace/platformsecret/platformsecret.go)
- [CWE-798: Use of Hard-coded
Credentials](https://cwe.mitre.org/data/definitions/798.html)
- [CWE-259: Use of Hard-coded
Password](https://cwe.mitre.org/data/definitions/259.html)
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
References
12 references
Impacted products
1 product
| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| Harness | Gitspace hardcoded |
Affected:
unknown
|
guessed |
{
"containers": {
"cna": {
"affected": [
{
"product": "Gitspace hardcoded",
"vendor": "Harness",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Khashayar Fereidani"
}
],
"descriptions": [
{
"lang": "en",
"value": "# harness Gitspace hardcoded password for every user account\n\n**Author:** Khashayar Fereidani\n**Disclosure Date:** 2026-09-24\n**Advisory:** https://fereidani.com/harness-gitspace-hardcoded-password-for-every-user-account\n**Contact:** https://fereidani.com/contact\n\n## Description\n\nGitspaces are Harness\u0027s hosted development environments: a container with\nthe user\u0027s source tree, running an SSH server and an IDE, with its ports\npublished on the host machine. Access is supposed to be controlled by a\nsecret the user configures. In practice the password of the Linux account\ninside every Gitspace container is the same public constant,\n`app/gitspace/secret/password_resolver.go:26`:\n\n```go\nconst defaultPassword = \"Harness@123\"\n\nfunc (p *PasswordResolver) Resolve(_ context.Context, _\nResolutionContext) (ResolvedSecret, error) {\nreturn ResolvedSecret{\nSecretValue: defaultPassword,\n}, nil\n}\n```\n\n`Resolve` discards the entire `ResolutionContext`, parameter by parameter.\nThe caller does pass the configured reference: `ResolveSecret` builds the\ncontext with `SecretRef: *config.GitspaceInstance.AccessKeyRef`\n(`app/gitspace/orchestrator/utils/secret.go:46`), but the resolver never\nreads it, so the user\u0027s choice of secret is ignored and the value cannot be\nrotated per instance. The wire set registers exactly this one resolver\n(`app/gitspace/secret/wire.go:20`), so every password-type resolution in the\nproduct returns the constant.\n\nThe resolved value becomes the account password inside the container. On\nresume, the orchestrator stores it\n(`app/gitspace/orchestrator/orchestrator_resume.go:50`) and the user setup\nscript applies it (`manage_user.sh` under\n`app/gitspace/orchestrator/utils/script_templates/`, line 49):\n\n```sh\nelif [ \"user_credentials\" = \"$accessType\" ] ; then\n echo \"$username:$accessKey\" | chpasswd\n```\n\nThe constant ships in the public repository, so it is known to anyone who\nhas read the source, and it is identical in every deployment, every release\nimage and every Gitspace instance. The `ssh_key` branch of the same script\nwrites the resolved value into `authorized_keys`\n(`manage_user.sh:43-46`); since that value is also the constant, that access\ntype simply does not work, which is further proof that the configured\nreference is never honored.\n\n## Reproduction\n\nThe resolver can be exercised directly. This in-package test asks it to\nresolve a configured secret reference:\n\n```go\npackage secret\n\nimport (\n\"context\"\n\"testing\"\n)\n\nfunc TestPocHardcodedPassword(t *testing.T) {\nresolved, err := (\u0026PasswordResolver{}).Resolve(context.Background(),\nResolutionContext{\nUserIdentifier: \"victim\",\nGitspaceIdentifier: \"gs-1\",\nSecretRef: \"my-configured-secret-ref\",\nSpaceIdentifier: \"space1\",\n})\nif err != nil {\nt.Fatal(err)\n}\nt.Logf(\"Resolve(SecretRef=%q) = %q\", \"my-configured-secret-ref\",\nresolved.SecretValue)\nif resolved.SecretValue != \"Harness@123\" {\nt.Fatalf(\"expected the shipped constant, got %q\", resolved.SecretValue)\n}\n}\n```\n\nObserved output on main at commit 912a1f3:\n\n```text\n--- PASS: TestPocHardcodedPassword (0.00s)\n poc_password_test.go:18:\nResolve(SecretRef=\"my-configured-secret-ref\") = \"Harness@123\"\n```\n\nWith a running deployment the account is then usable directly. Gitspace\nports are published as host port bindings\n(`app/gitspace/orchestrator/container/devcontainer_container_utils.go:281`),\nand the account name is the Gitspace owner\u0027s identifier\n(`config.GitspaceUser.Identifier` in the same plumbing), so anyone who can\nreach the published SSH port logs in with the public constant:\n\n```sh\nssh \u003cowner-identifier\u003e@\u003cgitspace-host\u003e -p \u003cpublished-port\u003e\n# password: Harness@123\n```\n\n## Impact\n\nUse of a hard-coded password (CWE-798, CWE-259). An attacker who can reach\na Gitspace\u0027s published SSH or IDE endpoint gets the owner\u0027s full\nenvironment: the source tree, any git credentials and tokens present in the\ncontainer, and the network position of the development sandbox. There is no\nper-instance secret to stop them, because the value is universal, public in\nthe source repository, and cannot be changed through configuration since\nthe resolver ignores the reference. Anyone who has ever read the source, or\nany attacker who obtained the constant from any other deployment, holds a\nvalid password for every Gitspace account in every Harness open source\ninstallation.\n\n## Solution\n\nMake the resolver earn its name. Two workable directions, in order of\npreference:\n\n- Honor the configured reference. The codebase already defines the seam:\n `PlatformSecret.FetchSecret(ctx, secretRef, spacePath)`\n (`app/gitspace/platformsecret/platformsecret.go:23`). Its only\n implementation currently ignores both the reference and the space path and\n returns its input masked (`gitnessplatformsecret.go:31`), so wire it to\n the existing secret service and have `PasswordResolver.Resolve` read\n `ResolutionContext.SecretRef` through it. Users can then set and rotate\n the real password as a proper secret.\n- Or drop shared passwords entirely: generate a random per-instance\n password with `crypto/rand` at Gitspace start and hand it to the owner\n through the control plane (the API or the IDE session), never storing a\n constant in the repository.\n\nEither way, a resolver that cannot produce a real secret should return an\nerror, not a known constant. Until a fix lands, treat every published\nGitspace port as a pre-authenticated login for the owner account: keep the\nports off public networks (firewall, VPN or bind them to loopback with an\nauthenticated tunnel in front), because no configuration change inside the\nproduct can change the password.\n\n## Timeline\n\n- 2026-09-24: Reported publicly as harness/harness#3725, found while\n scanning popular repositories with my static analyzer. The project\u0027s\n earlier security reports had gone unanswered; the current main branch\n (912a1f3) is affected.\n\n## References\n\n- [harness/harness#3725 - hardcoded password Harness@123 for every\ngitspace user account](https://github.com/harness/harness/issues/3725)\n- [harness/harness -\napp/gitspace/secret/password_resolver.go](https://github.com/harness/harness/blob/main/app/gitspace/secret/password_resolver.go)\n- [harness/harness -\napp/gitspace/orchestrator/utils/script_templates/manage_user.sh](https://github.com/harness/harness/blob/main/app/gitspace/orchestrator/utils/script_templates/manage_user.sh)\n- [harness/harness -\napp/gitspace/platformsecret/platformsecret.go](https://github.com/harness/harness/blob/main/app/gitspace/platformsecret/platformsecret.go)\n- [CWE-798: Use of Hard-coded\nCredentials](https://cwe.mitre.org/data/definitions/798.html)\n- [CWE-259: Use of Hard-coded\nPassword](https://cwe.mitre.org/data/definitions/259.html)\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-259",
"description": "CWE-259",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-798",
"description": "CWE-798",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-11-02T09:31:21Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/83"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Sep/83"
},
{
"url": "https://cwe.mitre.org/data/definitions/259.html"
},
{
"url": "https://cwe.mitre.org/data/definitions/798.html"
},
{
"url": "https://fereidani.com/contact"
},
{
"url": "https://fereidani.com/harness-gitspace-hardcoded-password-for-every-user-account"
},
{
"url": "https://github.com/harness/harness/blob/main/app/gitspace/orchestrator/utils/script_templates/manage_user.sh"
},
{
"url": "https://github.com/harness/harness/blob/main/app/gitspace/platformsecret/platformsecret.go"
},
{
"url": "https://github.com/harness/harness/blob/main/app/gitspace/secret/password_resolver.go"
},
{
"url": "https://github.com/harness/harness/issues/3725"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Sep/83"
],
"discovery": "EXTERNAL"
},
"title": "harness Gitspace hardcoded password for every user account",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0521",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/83",
"automated": true,
"contentSha256": "f19810a60e328f4e3ba50587b56ba3df204a96b93a94e9b3a1e1e526891f8058",
"evidenceScore": 7,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/83",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-09-24T14:42:12Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-11-02T09:31:21Z",
"dateUpdated": "2026-11-02T09:31:21Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0521"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
Loading…
Loading…
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.
Sightings
| Author | Source | Type | Date | Other |
|---|
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.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
Loading…
Loading…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Loading…
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.