Skip to content

Commit 3c0c934

Browse files
1 parent 3173c7d commit 3c0c934

4 files changed

Lines changed: 282 additions & 0 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-5ghq-42rg-769x",
4+
"modified": "2026-04-06T17:53:02Z",
5+
"published": "2026-04-06T17:53:02Z",
6+
"aliases": [
7+
"CVE-2026-35035"
8+
],
9+
"summary": "CI4MS: Company Information Public-Facing Page Full Platform Compromise & Full Account Takeover for All Roles & Privilege-Escalation via System Settings Company Information Stored DOM XSS",
10+
"details": "## Summary\n### **Vulnerability: Stored DOM XSS in main landing page via System Settings – Company Information (Persistent Payload Injection)**\n- Stored Cross-Site Scripting via Unsanitized Company Information Configuration Fields\n\n### Description\nThe application fails to properly sanitize user-controlled input within **System Settings – Company Information**. Several administrative configuration fields accept attacker-controlled input that is stored server-side and later rendered without proper output encoding.\n\nAffected fields include, but are not limited to:\n1. Company Name\n2. Slogan\n3. Company Phone\n4. Company Mobile\n5. Company Email\n6. Google Maps iframe link\n7. Company Logo and other media-related fields\n\nThese values are persisted in the database and rendered unsafely on **public-facing pages only**, such as the main landing page. **There is no execution in the administrative dashboard**—the vulnerability only impacts the public frontend. \n\n**Unlike the same-page stored DOM XSS vulnerability, this issue executes only on separate public-facing pages and not on the settings page itself.**\n\n### Affected Functionality\n- System Settings – Company Information configuration\n- **Public-facing page rendering (main landing page and other public pages)**\n- Storage and retrieval of company information values\n\n### Attack Scenario\n- An attacker injects a malicious JavaScript payload into one or more Company Information fields.\n- The application stores these values without sanitization or encoding.\n- The payload is rendered only on **public-facing pages**, including the main landing page.\n- The payload executes automatically in the browser context of **unauthenticated visitors and authenticated users** who access the public site.\n\n### Impact\n- Persistent Stored XSS\n- Execution of arbitrary JavaScript in visitors’ browsers\n- Potential account takeover if cookies are not secured\n- Platform-wide public-facing compromise\n- Full compromise of any user interacting with the affected pages\n\nEndpoints:\n- `/backend/settings/` (Company Information injection only, not execution)\n- Main landing page\n- Other public-facing application pages\n\n## Steps To Reproduce (POC)\n1. Navigate to System Settings → Company Information\n2. Insert an XSS payload into any Company Information field such as:\n`<img src=x onerror=alert(document.domain)>`\n3. Save the settings\n4. Visit the **public-facing main landing page** or other public pages\n5. Observe the XSS payload executing automatically\n\n## Remediation\n- Never use .html() again or any innerHTML-style like JS in your PHP, or any other sink, even if user inputs that flow into them are not clear, they still represent real world danger as an attacker can make use of this to exploit the application via XSS. And do HTML Encoding as much as possible and always do Sanitization, theres no sanitization there unfortunately. Also apply CSP, HttpOnly, SameSite, and Secure upon all application, they reduce severity of XSS & escalated-CSRF via XSS and do great jobs",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Packagist",
21+
"name": "ci4-cms-erp/ci4ms"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "0.31.2.0"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 0.31.1.0"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/ci4-cms-erp/ci4ms/security/advisories/GHSA-5ghq-42rg-769x"
45+
},
46+
{
47+
"type": "PACKAGE",
48+
"url": "https://github.com/ci4-cms-erp/ci4ms"
49+
},
50+
{
51+
"type": "WEB",
52+
"url": "https://github.com/ci4-cms-erp/ci4ms/releases/tag/0.31.2.0"
53+
}
54+
],
55+
"database_specific": {
56+
"cwe_ids": [
57+
"CWE-79"
58+
],
59+
"severity": "CRITICAL",
60+
"github_reviewed": true,
61+
"github_reviewed_at": "2026-04-06T17:53:02Z",
62+
"nvd_published_at": null
63+
}
64+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-6r34-94wq-jhrc",
4+
"modified": "2026-04-06T17:53:59Z",
5+
"published": "2026-04-06T17:53:59Z",
6+
"aliases": [
7+
"CVE-2026-35201"
8+
],
9+
"summary": "rdiscount has an Out-of-bounds Read",
10+
"details": "### Summary\n\nA signed length truncation bug causes an out-of-bounds read in the default Markdown parse path. Inputs larger than `INT_MAX` are truncated to a signed `int` before entering the native parser, allowing the parser to read past the end of the supplied buffer and crash the process\n\n### Details\n\nIn both public entry points:\n\n- `ext/rdiscount.c:97`\n- `ext/rdiscount.c:136`\n\n`RSTRING_LEN(text)` is passed directly into `mkd_string()`:\n\n```c\nMMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);\n```\n\n`mkd_string()` accepts `int len`:\n\n- `ext/mkdio.c:174`\n\n```c\nDocument * mkd_string(const char *buf, int len, mkd_flag_t flags)\n{\n struct string_stream about;\n\n about.data = buf;\n about.size = len;\n\n return populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK);\n}\n```\n\nThe parser stores the remaining input length in a signed `int`:\n\n- `ext/markdown.h:205`\n\n```c\nstruct string_stream {\n const char *data;\n int size;\n};\n```\n\nThe read loop stops only when `size == 0`:\n\n- `ext/mkdio.c:161`\n\n```c\nint __mkd_io_strget(struct string_stream *in)\n{\n if ( !in->size ) return EOF;\n\n --(in->size);\n\n return *(in->data)++;\n}\n```\n\nIf the Ruby string length exceeds `INT_MAX`, the value can truncate to a negative `int`. In that state, the parser continues incrementing `data` and reading past the end of the original Ruby string, causing an out-of-bounds read and native crash.\n\nAffected APIs:\n\n- `RDiscount.new(input).to_html`\n- `RDiscount.new(input).toc_content`\n\n### PoC\n\nCrash via `to_html`:\n\n```sh\nRUBYLIB=lib:ext ruby -e 'require \"rdiscount\"; n=2_200_000_000; s = \"a\" * n; warn \"built=#{s.bytesize}\"; RDiscount.new(s).to_html\"'\n```\nresult:\n\n- `built=2200000000`\n- Ruby terminates with `[BUG] Segmentation fault`\n- top control frame: `CFUNC :to_html`\n\nsame result with `toc_content`\n\n### Impact\n\nThis is an out-of-bounds read with the main issue being reliable denial-of-service. Impacted is limited to deployments parses attacker-controlled Markdown and permits multi-GB inputs.\n\n### Fix\n\njust add a checked length guard before the `mkd_string()` call in both public entry points:\n\n- `ext/rdiscount.c:97`\n- `ext/rdiscount.c:136`\nex: \n```c\nVALUE text = rb_funcall(self, rb_intern(\"text\"), 0);\nlong text_len = RSTRING_LEN(text);\nVALUE buf = rb_str_buf_new(1024);\nCheck_Type(text, T_STRING);\n\nif (text_len > INT_MAX) {\n rb_raise(rb_eArgError, \"markdown input too large\");\n}\n\nMMIOT *doc = mkd_string(RSTRING_PTR(text), (int)text_len, flags);\n```\n\nThe same guard should be applied in `rb_rdiscount_toc_content()` before its `mkd_string()` call.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "RubyGems",
21+
"name": "rdiscount"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "1.3.1.1"
29+
},
30+
{
31+
"fixed": "2.2.7.4"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/davidfstr/rdiscount/security/advisories/GHSA-6r34-94wq-jhrc"
42+
},
43+
{
44+
"type": "WEB",
45+
"url": "https://github.com/davidfstr/rdiscount/commit/b1a16445e92e0d12c07594dedcdc56f80b317761"
46+
},
47+
{
48+
"type": "PACKAGE",
49+
"url": "https://github.com/davidfstr/rdiscount"
50+
},
51+
{
52+
"type": "WEB",
53+
"url": "http://github.com/davidfstr/rdiscount/releases/tag/2.2.7.4"
54+
}
55+
],
56+
"database_specific": {
57+
"cwe_ids": [
58+
"CWE-125"
59+
],
60+
"severity": "MODERATE",
61+
"github_reviewed": true,
62+
"github_reviewed_at": "2026-04-06T17:53:59Z",
63+
"nvd_published_at": null
64+
}
65+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-cjg8-h5qc-hrjv",
4+
"modified": "2026-04-06T17:55:14Z",
5+
"published": "2026-04-06T17:55:14Z",
6+
"aliases": [
7+
"CVE-2026-35492"
8+
],
9+
"summary": "kedro-datasets has a path traversal vulnerability in PartitionedDataset that allows arbitrary file write",
10+
"details": "### Impact\n\nPartitionedDataset in kedro-datasets was vulnerable to path traversal. Partition IDs were concatenated directly with the dataset base path without validation. An attacker or malicious input containing .. components in a partition ID could cause files to be written outside the configured dataset directory, potentially overwriting arbitrary files on the filesystem.\nUsers of PartitionedDataset with any storage backend (local filesystem, S3, GCS, etc.) are affected.\n\n### Patches\nYes. The vulnerability has been patched in kedro-datasets version 9.3.0.\nUsers should upgrade to kedro-datasets >= 9.3.0. The fix normalizes constructed paths using `posixpath.normpath` and validates that the resolved path remains within the dataset base directory before use, raising a `DatasetError` if the path escapes the base directory.\n\n### Workarounds\nUsers who cannot upgrade should validate partition IDs before passing them to PartitionedDataset, ensuring they do not contain `..` path components.\n\n### References\nFix: https://github.com/kedro-org/kedro-plugins/pull/1346\nReport: https://github.com/kedro-org/kedro/issues/5452",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "PyPI",
21+
"name": "kedro-datasets"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "9.3.0"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/kedro-org/kedro-plugins/security/advisories/GHSA-cjg8-h5qc-hrjv"
42+
},
43+
{
44+
"type": "WEB",
45+
"url": "https://github.com/kedro-org/kedro/issues/5452"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/kedro-org/kedro-plugins/pull/1346"
50+
},
51+
{
52+
"type": "WEB",
53+
"url": "https://github.com/kedro-org/kedro-plugins/commit/65115f76b872217317734b6bde8927170c98fc4b"
54+
},
55+
{
56+
"type": "PACKAGE",
57+
"url": "https://github.com/kedro-org/kedro-plugins"
58+
},
59+
{
60+
"type": "WEB",
61+
"url": "https://github.com/kedro-org/kedro-plugins/releases/tag/kedro-datasets-9.3.0"
62+
}
63+
],
64+
"database_specific": {
65+
"cwe_ids": [
66+
"CWE-22"
67+
],
68+
"severity": "MODERATE",
69+
"github_reviewed": true,
70+
"github_reviewed_at": "2026-04-06T17:55:14Z",
71+
"nvd_published_at": null
72+
}
73+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-f2g3-hh2r-cwgc",
4+
"modified": "2026-04-06T17:53:40Z",
5+
"published": "2026-04-06T17:53:40Z",
6+
"aliases": [
7+
"CVE-2026-35172"
8+
],
9+
"summary": "Distribution: stale blob access resurrection via repo-scoped redis descriptor cache invalidation",
10+
"details": "## summary:\ndistribution can restore read access in `repo a` after an explicit delete when `storage.cache.blobdescriptor: redis` and `storage.delete.enabled: true` are both enabled. the delete path clears the shared digest descriptor but leaves stale repo-scoped membership behind, so a later `Stat` or `Get` from `repo b` repopulates the shared descriptor and makes the deleted blob readable from `repo a` again.\n\n## Severity\n\nHIGH\n\njustification: this is a repo-local authorization bypass after explicit delete, with concrete confidentiality impact and no requirement for write access after the delete event. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N (7.5). CWE-284.\n\n# affected version\n\n- repository: https://github.com/distribution/distribution\n- commit: ab67ffa0bda3712991194841d0fde727464feeb9\n- affected versions: \\<= 3.0.x, \\<= 2.8.x when redis blob descriptor cache and delete are both enabled\n- affected file:\n - https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/cache/redis/redis.go#L212-L226\n- related callsites:\n - https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/cache/cachedblobdescriptorstore.go#L66-L76\n - https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/linkedblobstore.go#L218-L224\n - https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/linkedblobstore.go#L396-L403\n\n# details\n\nthe backend access model is repository-link based: once `repo a` deletes its blob link, later reads from `repo a` should continue returning `ErrBlobUnknown` even if the same digest remains linked in `repo b`.\n\nthe issue is the split invalidation path in the redis cache backend:\n\n1. `linkedBlobStore.Delete` calls `blobAccessController.Clear` during repository delete handling.\n2. `cachedBlobStatter.Clear` forwards that invalidation into the cache layer.\n3. `repositoryScopedRedisBlobDescriptorService.Clear` checks that the digest is a member of `repo a`, but then only calls `upstream.Clear`.\n4. `upstream.Clear` deletes the shared digest descriptor and does not remove the digest from the repository membership set for `repo a`.\n5. when `repo b` later stats or gets the same digest, the shared descriptor is recreated.\n6. `repositoryScopedRedisBlobDescriptorService.Stat` for `repo a` accepts the stale membership and now trusts the repopulated shared descriptor, restoring access in the repository that already deleted its link.\n\nthis creates a revocation gap at the repository boundary. the blob is briefly inaccessible from `repo a` right after delete, which confirms the backend link was removed, and then becomes accessible again only because stale redis membership survived while a peer repository repopulated the shared descriptor.\n\n# attack scenario\n\n1. an operator runs distribution with `storage.cache.blobdescriptor: redis` and `storage.delete.enabled: true`.\n2. the same digest exists in both `repo a` and `repo b`.\n3. the operator deletes the blob from `repo a` and expects repository-local access to be revoked.\n4. `repo a` correctly returns `blob unknown` immediately after the delete.\n5. an anonymous or unprivileged user requests the same digest from `repo b`, which still legitimately owns it and repopulates the shared descriptor.\n6. a later request for the digest from `repo a` succeeds again because stale repo-a membership was never revoked from redis.\n\n# PoC\n\nattachment: `poc.zip`\n\nthe attached PoC is a deterministic integration harness using `miniredis` and the pinned distribution source tree.\n\n## steps to reproduce\n\ncanonical:\n\n```bash\nunzip -q -o poc.zip -d poc\ncd poc\nmake canonical\n```\n\nexpected output:\n\n```text\n[CALLSITE_HIT]: repositoryScopedRedisBlobDescriptorService.Clear->upstream.Clear->repositoryScopedRedisBlobDescriptorService.Stat\n[PROOF_MARKER]: repo_a_access_restored=true repo_a_delete_miss=true repo_b_peer_warm=true\n[IMPACT_MARKER]: repo_a_post_delete_read=true confidentiality_boundary_broken=true\n```\n\ncontrol:\n\n```bash\nunzip -q -o poc.zip -d poc\ncd poc\nmake control\n```\n\nexpected control output:\n\n```text\n[CALLSITE_HIT]: repositoryScopedRedisBlobDescriptorService.Clear->repositoryScopedRedisBlobDescriptorService.Stat\n[NC_MARKER]: repo_a_access_restored=false repo_b_peer_warm=true\n```\n\n# expected vs actual\n\n- expected: after `repo a` deletes its blob link, later reads from `repo a` should keep returning `blob unknown` even if `repo b` still references the same digest and warms cache state.\n- actual: `repo a` first returns `blob unknown`, then `repo b` repopulates the shared descriptor, and `repo a` serves the deleted digest again through stale repo-scoped redis membership.\n\n# impact\n\nthe confirmed impact is repository-local confidentiality failure after explicit delete. an operator can remove sensitive content from `repo a`, observe revocation working immediately after the delete, and still have the same content become readable from `repo a` again as soon as `repo b` refreshes the shared descriptor for that digest.\n\nthis is not a claim about global blob deletion. the bounded claim is that repository-local revocation fails, which breaks the expectation that deleting a blob link from one repository prevents further reads from that repository.\n\n# remediation\n\nthe safest fix is to make redis invalidation revoke repo-scoped state together with the backend link deletion. in practice that means removing the digest from the repository membership set, deleting the repo-scoped descriptor hash, and keeping that cleanup atomic enough that peer-repository warming cannot restore access in the repository that already deleted its link.\n\n[poc.zip](https://github.com/user-attachments/files/25813827/poc.zip)\n[PR_DESCRIPTION.md](https://github.com/user-attachments/files/25813828/PR_DESCRIPTION.md)\n[attack_scenario.md](https://github.com/user-attachments/files/25813829/attack_scenario.md)",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/distribution/distribution/v3"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "3.1.0"
32+
}
33+
]
34+
}
35+
]
36+
},
37+
{
38+
"package": {
39+
"ecosystem": "Go",
40+
"name": "github.com/distribution/distribution"
41+
},
42+
"ranges": [
43+
{
44+
"type": "ECOSYSTEM",
45+
"events": [
46+
{
47+
"introduced": "0"
48+
},
49+
{
50+
"last_affected": "2.8.3"
51+
}
52+
]
53+
}
54+
]
55+
}
56+
],
57+
"references": [
58+
{
59+
"type": "WEB",
60+
"url": "https://github.com/distribution/distribution/security/advisories/GHSA-f2g3-hh2r-cwgc"
61+
},
62+
{
63+
"type": "WEB",
64+
"url": "https://github.com/distribution/distribution/commit/078b0783f239b4115d1a979e66f08832084e9d1d"
65+
},
66+
{
67+
"type": "PACKAGE",
68+
"url": "https://github.com/distribution/distribution"
69+
}
70+
],
71+
"database_specific": {
72+
"cwe_ids": [
73+
"CWE-284"
74+
],
75+
"severity": "HIGH",
76+
"github_reviewed": true,
77+
"github_reviewed_at": "2026-04-06T17:53:40Z",
78+
"nvd_published_at": null
79+
}
80+
}

0 commit comments

Comments
 (0)