Frozen Laravel 6 / PHP 7.2 demo & staging fork of the A-List backend. Last touched Nov 2020 — committed live secrets, an entirely unauthenticated admin panel, an EOL stack, and a deployment status that is still unknown.
alist-portal (both started 2020-08-31); this one froze on 2020-11-02 while alist-portal continued evolving to Laravel 11 / PHP 8.2 (last commit 2026-05-08).error_log and supervisord.conf (/home2/frinkae/public_html/Development-Alist/, /home/parhaman/public_html/development-alist/) confirm it ran on cPanel. Whether anything still serves traffic from this code is the single most important question to answer before doing anything else.APP_DEBUG=true; dompdf RCE/SSRF reachable from the PDF job).database/seeds/step*.php have been archived. Until then, treat every committed credential as breached and rotate it immediately.| Category | Technology | Version | Notes |
|---|---|---|---|
| Language | PHP | ^7.2 | EOL 2019-11-30. No security patches. |
| Framework | Laravel | ^6.2 (LTS) | LTS support ended 2022-01-25. |
| Database | MySQL / MariaDB | MariaDB 10.1 per parhamandco.sql dump header | Connection parhaman_development_alist. |
| Queue | Supervisor + queue:listen | — | a-list-supervisorconf.config targets /home/parhaman/public_html/development-alist/artisan. |
| Frontend build | Laravel Mix / webpack | per webpack.mix.js | Standard Mix; no JS framework. |
| Auth | Laravel built-in | laravel/ui ^1.1 | Registration disabled in routes/web.php — but re-enabled inside /admin (see ALD-03). |
| barryvdh/laravel-dompdf | ^0.8.6 | Old dompdf line; known RCE/SSRF CVEs, reachable via CreatePdfJob. | |
| Excel I/O | maatwebsite/excel | ^3.1 | Wraps phpspreadsheet 1.15.0; used by admin exports/imports. |
| Error monitoring | sentry/sentry-laravel | ^1.9 | Old SDK; portal is on 4.x. |
| Mail tracking | jdavidbakr/mail-tracker | 3.* | Recently re-added in final commit "Mailtacker Files". |
| 3rd party | rapidwebltd/php-google-contacts-v3-api | ^2.0 | OAuth callback at /contacts in routes/web.php. |
| Dev tools | facade/ignition | ^1.4 (1.16.3 locked) | Vulnerable line — CVE-2021-3129 RCE when APP_DEBUG=true (which .env_4-May-2020 has). |
| Testing | phpunit/phpunit | ^8.0 | Default Laravel scaffold; no meaningful tests committed. |
Monolithic Laravel 6 web app served via cPanel/LSAPI behind an .htaccess rewrite that funnels every request through /public/index.php. Eloquent models live flat under app/ (pre-Laravel-8 convention). Background work (queue worker) is driven by Supervisor. Inbound routes split across web.php (public site & offer flow), admin.php (admin panel), api.php (minimal — 15 lines), chat_agent.php, and channels.php.
This security review was conducted by reading the source directly (controllers, routes, middleware, config, composer.lock, .htaccess and committed artifacts) and tracing each tainted value from request input to its sink. Every finding below is backed by a code citation and was independently re-verified; over-stated raw findings were corrected or downgraded rather than dropped. Severity is assigned with CVSS 3.1 and mapped to OWASP Top 10 2021 and CWE; exploitability of host-dependent issues is gated on whether a live deployment still exists.
secrets-in-git-scan
broken-access-control-review
sql-injection-source-to-sink
ssrf-and-file-inclusion-review
vulnerable-dependency-triage
security-misconfiguration-sweep
auth-and-session-review
owasp-top-10-coverage-map
cvss-severity-scoring
remediation-roadmap-builder
a-list-demo is a frozen Laravel 6 / PHP 7.2 fork (last commit 2020-11-02, EOL stack with no security patches) that ships an exceptionally large, code-confirmed attack surface. The entire ~70-route admin panel is unauthenticated at the route layer (the 'admin' middleware group is a copy of 'web' with no Authenticate), and even where controllers call $this->middleware('auth') the default 'web' guard has no role/is_admin concept, so any users-table account is a full admin — and Auth::routes() is re-enabled inside /admin, letting an anonymous attacker self-register straight to admin. From there, multiple raw-string DB::select sinks (UsersPreviews, FoodOffers, Venues, Audit, Admin controllers) yield UNION/blind SQL injection, and a DomPDF job renders attacker-supplied HTML with isRemoteEnabled=true (SSRF to cloud metadata + file:// read). Live secrets are committed and unrotated since 2020 — production MySQL password, Gmail SMTP password for info@alist.ae, the Laravel APP_KEY, a Google OAuth client secret + non-expiring refresh token, four Slack webhooks, a Monday write token — plus a DB dump with an admin bcrypt hash and a 24 MB backup zip embedding a second app's secrets and an even older RCE-vulnerable Ignition. If any host still serves this code (cPanel breadcrumbs strongly suggest it once did), it is trivially and remotely compromisable; the single most urgent operational question is whether demo/dev-alist is still online, and every committed credential must be treated as breached and rotated immediately.
.env (DB, Gmail SMTP, APP_KEY), .config.json (Google OAuth secret + non-expiring refresh token + API key), config/thirdparty.php (4 Slack webhooks + Monday write JWT), parhamandco.sql (admin bcrypt hash + PII), and parhamandco.zip (embeds a second app's .env, APP_KEY, Mailtrap creds). Matches the org-wide "rotate-before-refactor" priority from the May 2026 audit.middleware('auth') on the default guard with no role model, Auth::routes() re-enabled under /admin, and homegrown auth via raw session-key presence checks. No object-level/ownership checks anywhere.DB::select is a pervasive idiom across admin controllers (at least 5 distinct injectable endpoints) despite a safe Query Builder branch existing in the same file — copy-paste of an unsafe pattern rather than an isolated mistake.sha1(date) without a secret, the literal string 'admin' in a URL segment, base64('prive') as a privilege gate, and Hashids with the default empty salt at 30+ call sites (publicly reversible)..htaccess (!-f bypass): phpinfo() scripts, error_log, composer.lock, .sql dump, 24 MB zip, dated .env copies — a broad information-exposure / SBOM-leak cluster.same_site=null + secure=false, no TrustHosts, no security response headers, allow_url_include=On — each amplifies the blast radius of the primary bugs.| Category | Status | Notes |
|---|---|---|
| A01:2021 — Broken Access Control | vuln | Unauthenticated admin panel, auth-as-authorization with no role, self-registration to admin, unauth state-changing offer endpoints, IDOR via default-salt Hashids, GET-based CSRF (ALD-01/02/03/15/16/22/26/27). |
| A02:2021 — Cryptographic Failures | vuln | Live DB/SMTP/APP_KEY, Google OAuth secret+refresh token, Slack/Monday tokens, and a bcrypt-hash DB dump all committed (ALD-06/08/13/14). |
| A03:2021 — Injection | vuln | Five confirmed raw-concatenation SQLi sinks across admin controllers plus one theoretical second-order (ALD-04/17/18/19/20/31). |
| A04:2021 — Insecure Design | partial | No defense-in-depth: bare-auth-as-authorization, URL-literal/base64 privilege gates, GET for destructive actions — design-level rather than a single bug (ALD-02/22/25). |
| A05:2021 — Security Misconfiguration | vuln | APP_DEBUG=true in prod, phpinfo()/error_log/secret files web-reachable via permissive .htaccess, insecure cookies, /run_queue, allow_url_include=On, no security headers (ALD-10/11/21/23/24/28/29/30). |
| A06:2021 — Vulnerable and Outdated Components | vuln | EOL PHP 7.2 / Laravel 6; Ignition 1.16.3 (CVE-2021-3129), dompdf/phpspreadsheet/guzzle/flysystem CVEs; embedded 2nd app with Ignition 1.11.2 (ALD-07/09/10/12). |
| A07:2021 — Identification and Authentication Failures | vuln | Weak primitives as auth tokens (sha1(date), base64('prive'), 'admin' literal), session-key presence check, no admin guard (ALD-25/27, and ALD-02/03). |
| A08:2021 — Software and Data Integrity Failures | partial | opis/closure 3.6.0 deserialization gadget present and DomPDF renders untrusted HTML; no signed/verified update pipeline, but no confirmed standalone deserialization sink reached by attacker input (touched by ALD-05/12). |
| A09:2021 — Security Logging and Monitoring Failures | partial | Committed error_log shows ad-hoc logging; no centralized/alerting evidence and APP_DEBUG leaks rather than logs securely. Not separately scored. |
| A10:2021 — Server-Side Request Forgery (SSRF) | vuln | DomPDF job with isRemoteEnabled=true rendering raw attacker HTML (ALD-05); dormant cURL SSRF in Instagram rule (ALD-32). |
| API Top 10 (note) | n/a | Not an API tier — routes/api.php is 15 lines and the app is server-rendered Blade; the AJAX/JSON admin endpoints are covered under A01/A03 above. |
| Mobile Top 10 (M1-M10) | n/a | No mobile client in this repo (server-side Laravel web app); MASVS / Mobile Top 10 not applicable. |
The admin route group applies only a URL prefix and namespace; the 'admin' middleware group it runs under contains no authentication middleware. The dedicated AdminAuthValidate middleware exists but is wired only to a commented-out route. GET admin endpoints whose controllers also lack a constructor auth check are reachable with no login at all.
GET /admin/exportSignups/approved (or /admin/usersList) and receives the full signups table; then GET /admin/blockORsuspend?... to disrupt accounts. No login, token, or CSRF needed for the GET endpoints.Unauthenticated read/export of all influencer PII (signups: name, email, mobile, Instagram, nationality, DOB) via GET /admin/usersList and /admin/exportSignups, plus block/suspend, offer/venue mutation, and audit-PDF deletion. Confidentiality, integrity, and availability all impacted with zero credentials.
Route::group(['prefix'=>'admin','namespace'=>'Admin','middleware'=>['adminAuthValidate']], ...)) AND add \Illuminate\Auth\Middleware\Authenticate to the 'admin' middleware group in Kernel.php. Back it with a real admin guard/role. Add a route-coverage test asserting every /admin/* route returns 401/redirect when unauthenticated.Confirmed by reading routes/admin.php, RouteServiceProvider, and Kernel.php. Many admin controllers DO call middleware('auth') in their constructor (ALD-02), so those endpoints still require some authenticated users-table session; GET routes on controllers without that constructor (and the route group's missing gate) are the fully-open ones. Severity remains P0 because ALD-02/ALD-03 collapse 'authenticated' into 'admin'.
Every admin controller calls $this->middleware('auth') with no guard, resolving the default 'web' guard backed by the users table. The User model/users table has no role or is_admin attribute, so authentication equals authorization: any users-table account is implicitly a full administrator. No per-action privilege check exists anywhere.
Vertical privilege escalation — any single users-table account (including a self-registered one, see ALD-03) yields complete administrative control. Any credential compromise of any account is full platform compromise.
is_admin/role column and a dedicated admin guard, gate every admin action via a Gate/Policy or middleware('can:...'), and specify the guard explicitly ($this->middleware('auth:admin')). Never treat bare authentication as authorization.Confirmed: AdminController.php:25-28, config/auth.php has only 'web' and 'chat_agent' guards, User model has no role field.
web.php disables registration, but admin.php calls bare Auth::routes() inside the /admin prefix, re-registering POST /admin/register backed by the stock RegisterController. It creates a users-table row and redirects to /admin/dashboard. Because any users-table account is treated as admin (ALD-02), an anonymous attacker can register themselves into full admin in one request.
/admin/register, is redirected to /admin/dashboard, and now holds a fully-privileged account.Anonymous attacker to administrator in a single POST. Defeats any future login gate that merely checks for an authenticated users-table account.
Auth::routes() from inside /admin (use ['register'=>false] consistently, register only login/logout for admin). Disable public registration for the admin guard; provision admin accounts out of band. Confirm POST /admin/register returns 404/403 after the fix.Confirmed: routes/admin.php:14 bare Auth::routes() vs routes/web.php:16 register=>false; RegisterController redirects to /admin/dashboard.
filterPreviews builds a large raw SQL string for DB::select by concatenating request-controlled venues, instagram_followers, search value, and pagination start/length with zero parameterization. str_replace('Pending',...) does not neutralize SQL metacharacters. The IN lists, WHERE/LIKE clauses, and LIMIT are all injectable.
venues=0) UNION SELECT email,password,... FROM users-- or start=0 UNION SELECT ... in the DataTables request and reads arbitrary tables.Full database read (and write/file ops depending on grants) including signups PII and credentials. Error-based extraction is trivial with APP_DEBUG=true. A low-privilege (or self-registered) authenticated session suffices.
? placeholders, build IN lists with placeholder arrays, and integer-cast pagination ((int)$start/(int)$length).Confirmed by reading UsersPreviewsController.php:185-282. Tainted values traced from request to query string.
auditPdfDownload passes request pdf_content verbatim to CreatePdfJob, which renders it through DomPDF with isRemoteEnabled=true; the Blade template prints it with {!! !!}. Attacker HTML (img/link/@import to http://169.254.169.254/, http://127.0.0.1:port, or file:///etc/passwd) forces server-side fetches, and the resulting PDF is saved under the public web root for retrieval.
pdf_content=<img src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"> to /admin/auditPdfDownload, then downloads the generated PDF from public/audit_pdf/ to read the fetched IAM credentials.Server-side fetch of arbitrary internal/cloud/file URLs (instance-metadata/IAM credential theft, internal service access, local file read) with exfiltration via the web-readable PDF. Reachable by any authenticated session — which, per ALD-01/02/03, an anonymous attacker can obtain.
isRemoteEnabled=false in CreatePdfJob (an audit table needs no remote assets). Never render user-supplied HTML with {!! !!}; build the PDF from validated structured fields. If remote assets are truly needed, use a strict allowlist blocking RFC1918/link-local/loopback and non-http(s) schemes, and set allow_url_fopen=Off. Move generated PDFs out of the public root.Confirmed the inline isRemoteEnabled in AuditController is COMMENTED OUT (lines 675-688), but the ACTIVE path dispatches CreatePdfJob whose handle() genuinely sets isRemoteEnabled=true. PR set to L (not H) because admin access is not actually a barrier given ALD-01/03; Scope:Changed for cross-zone fetch.
The production env file (APP_ENV=production) is committed as a dated copy bypassing .gitignore, exposing the live MySQL credentials, the Gmail SMTP password for info@alist.ae, and the Laravel APP_KEY. The same DB password is a hardcoded fallback in config/database.php, leaking even without the .env file.
DB_PASSWORD and connects to MySQL, or authenticates SMTP as info@alist.ae, or uses APP_KEY to forge session/cookie payloads.Full DB compromise if MySQL is reachable. SMTP password enables sending mail as info@alist.ae (phishing/BEC) and possibly broader Google account access. The APP_KEY enables forging signed cookies and decrypting/forging encrypted sessions, defeating authentication.
APP_KEY. Remove the config/database.php hardcoded fallback (use bare env()). Purge .env_4-May-2020 from history (filter-repo/BFG). Tighten .gitignore to .env* and add Gitleaks/TruffleHog pre-commit + CI gates.Confirmed all values present in .env_4-May-2020 and the fallback in config/database.php:53. File tracked and present since initial commit.
facade/ignition <2.5.2 has an unauthenticated RCE: the execute-solution endpoint plus php://filter log-file manipulation allows writing attacker-controlled content and including it. Exploitation requires only debug mode, which the committed production env enables.
APP_DEBUG=true, an attacker hits the Ignition execute-solution endpoint with a php://filter chain to write and include a PHP payload, gaining RCE without credentials.Unauthenticated remote code execution as the web user on any internet-facing instance using this env. Combined with the committed DB/SMTP secrets, full data exfiltration and mail abuse follow. Mature weaponized exploits exist (Laravel-RCE / phpggc).
APP_DEBUG=false in every deployed environment immediately (closes the RCE alone). Upgrade ignition to >=2.5.2 (needs Laravel 8+) or decommission this EOL stack. Confirm no live host serves this code; rotate the exposed APP_KEY.Confirmed ignition 1.16.3 in composer.lock and APP_DEBUG=true in committed env. Exploitability conditional on a live host (status unknown) — confidence 'confirmed' for the vulnerable configuration, realistic exposure gated on deployment.
Repo-root .config.json holds a complete Google OAuth2 credential set: client_id, client_secret, an AIza API key, and a long-lived offline refresh token. The refresh token plus client_id/secret mint fresh access tokens indefinitely with no user interaction. The unauthenticated /contacts route additionally echoes a refresh token to whoever completes the OAuth dance.
Programmatic read/modify of the A-List Google Contacts/People directory (influencer/vendor PII), OAuth client impersonation via the secret, and API-key abuse against enabled Google APIs (quota/billing).
.config.json from history; add *.config.json to .gitignore. Remove or auth-gate the /contacts and /authorise-application routes and replace echo/var_dump with logging.Confirmed .config.json contents and that the file is tracked. /contacts echo confirmed in routes/web.php:53.
The app targets PHP 7.2 (EOL) and Laravel 6 (support ended), so the runtime, framework, and bundled Symfony 4.4/5.1 components receive no security fixes. Framework constraints cap all dependencies at long-unmaintained versions — a structural supply-chain risk.
Cumulative, ever-growing exposure to disclosed CVEs in runtime/framework/components with no upstream remediation path. Any newly weaponized PHP 7.2 / Laravel 6 / Symfony 4.4 bug is exploitable indefinitely on a deployed instance.
Confirmed versions in composer.json/composer.lock and ea-php72 handler references.
A 24.5 MB archive at the repo root is a full backup of a separate client Laravel app with its own .env (APP_KEY, Mailtrap MAIL_PASSWORD), composer.lock and bundled vendor tree, including an even older CVE-2021-3129-vulnerable Ignition (1.11.2). Per the permissive .htaccess (ALD-11) it is directly downloadable if any host serves the repo.
Leakage of a second project's APP_KEY (session/cookie forgery for that app) and Mailtrap mail credential, plus a ready-to-exploit second vulnerable codebase. Also bloats clone surface.
parhamandco.zip from the repo and purge from history (filter-repo/BFG). Rotate the embedded app's APP_KEY and Mailtrap credential. Confirm that app is decommissioned or separately remediated.Confirmed via unzip: embedded .env present with APP_KEY/APP_DEBUG/Mailtrap MAIL_PASSWORD. Raw finding overstated DB_PASSWORD and PUSHER_APP_SECRET as populated — both are EMPTY in the embedded .env; corrected here. CVSS lowered to 8.6 / I:L accordingly.
The Laravel-without-docroot .htaccess rewrites only non-existent paths into /public/. Files that physically exist at the app root (.env_4-May-2020, .config.json, composer.lock, parhamandco.zip/.sql, error_log, info.php) are served verbatim because !-f skips them and there are no deny rules. composer.lock alone hands attackers the full SBOM.
https://host/composer.lock to map exact dependency versions, then https://host/.config.json and https://host/.env_4-May-2020 to harvest secrets directly.Unauthenticated disclosure of the software bill of materials (removing the recon barrier for ALD-07/09/12) plus direct download of committed secret/backup/log files. Lowers attacker cost for every dependency CVE.
/public/ (move app out of docroot) or add explicit <FilesMatch> deny rules for .env*/.json/.lock/.zip/.sql/.log and phpinfo scripts. Remove the committed secret/diagnostic files and rotate their secrets.Confirmed .htaccess rewrite logic and that all named files are tracked at root. Exposure conditional on a live host.
Several directly/transitively used packages are pinned below patched versions and are reachable from controller/job code. dompdf 0.8.6 (CVE-2022-28368 RCE via CSS @font-face when rendering attacker-influenced HTML — directly relevant given ALD-05, and CVE-2021-3838 SSRF) is invoked from CreatePdfJob; phpspreadsheet 1.15.0 is exposed to XXE/formula-injection on user-supplied imports; guzzle/psr7 carry header-parsing/credential-leak-on-redirect CVEs; flysystem 1.1.3 has a path-traversal flaw. All are capped by the EOL framework.
pdf_content (ALD-05) to trigger dompdf CVE-2022-28368, or uploads a malicious spreadsheet to an Excel-import endpoint to trigger an XXE in phpspreadsheet.Where attacker data reaches PDF generation, RCE/SSRF chains are plausible; spreadsheet import can yield XXE/file disclosure; HTTP-client CVEs can leak credentials on redirect. None can be cleanly patched in place.
dompdf>=2.0.1, phpspreadsheet>=1.18, guzzle 6.5.8, psr7 1.8.4, flysystem 1.1.4) — but the clean fix is migrating this functionality to alist-portal and retiring the fork. Treat AuditController/CreatePdfJob HTML and Excel imports as untrusted.Confirmed all versions in composer.lock and reachability of dompdf/phpspreadsheet from controllers/jobs. Related CVEs: CVE-2021-3838 (dompdf SSRF), CVE-2022-31090/31091 (guzzle), CVE-2022-24775 (psr7), CVE-2021-32708 (flysystem).
config/thirdparty.php (tracked) hardcodes four production Slack incoming-webhook URLs and a Monday.com API token with me:write scope; both are referenced by application code, confirming they are in-use. config/thirdparty.php_bkp commits an additional set.
api.monday.com/v2 to exfiltrate/modify applicant PII boards.Slack webhook leak permits posting spoofed/phishing messages into signup/approval/vendor channels. The Monday token permits read/modify of boards storing applicant PII via the Monday GraphQL API. Both usable directly from the committed repo.
_bkp ones), move to env() references, delete config/thirdparty.php_bkp, purge values from history, and add CI scanning for hooks.slack.com URLs and JWTs.Confirmed by reading config/thirdparty.php; the offers/signup/approve webhooks share one URL and one ('offers' original) is commented out — corrected to note the active set. CVSS lowered slightly (S:U, no integrity-of-other-component beyond messaging) vs raw 8.6.
A phpMyAdmin SQL dump committed at the repo root contains the bcrypt hash for admin@parhamandco.com and signup PII (names, emails, phones, Instagram handles, nationality).
parhamandco.sql, extracts the admin bcrypt hash, cracks it offline, and logs into the admin panel.The admin bcrypt hash can be cracked offline; a weak password yields admin login. The PII is a privacy/GDPR exposure and a phishing target list. Harvestable by anyone who clones the repo or downloads from a live host.
parhamandco.sql from the repo and history (filter-repo/BFG). Rotate the admin credential. Handle the leaked PII per data-breach policy. Never commit DB dumps; add *.sql to .gitignore.Confirmed bcrypt hash and PII rows present at parhamandco.sql:134 and surrounding.
VenueOfferController runs under the 'web' group (session/CSRF only) with no auth middleware. Its GET routes are state-changing yet take object IDs straight from request input. deleteOfferUsers deletes invitations, resets user-to-offer bindings, and emails cancellations for attacker-chosen IDs; proceedOffer/unBlockOffer similarly mutate state. No ownership or authentication check exists.
GET /deleteOfferUsers to corrupt offer assignments and trigger cancellation emails to arbitrary users, all without authentication.Unauthenticated integrity/availability impact on the offers subsystem: arbitrary cancellation/reassignment of offer claims, clearing user bindings (releasing/redistributing offer codes), and spamming arbitrary recipients with cancellation emails. Business-logic abuse + DoS against legitimate claims.
Confirmed VenueOfferController has no constructor/middleware and the routes are in the unauthenticated web group; deleteOfferUsers/proceedOffer bodies confirmed.
Public, unauthenticated routes resolve sensitive objects from URL/body identifiers obfuscated with Hashids instantiated using the default empty salt — publicly reversible/forgeable, effectively sequential integers in disguise. No endpoint verifies the requester owns the referenced user_id/offer_id. reviewSave persists a review on behalf of any user; /offerView uses base64('prive') as a guessable access token.
reviewSave with arbitrary userid/offerid to forge reviews.Horizontal IDOR: enumerate/disclose any influencer's review submissions and screenshots, forge reviews on behalf of arbitrary users, and view non-published offers via the static base64('prive') token. The default salt lets an attacker mint valid tokens for arbitrary IDs offline.
Confirmed new Hashids() with no salt at the cited sites and unauthenticated routes; base64('prive') and 'admin' gates confirmed in OfferController.php:48-67.
venueDropListAuto concatenates the unsanitized keyword into a single-quoted LIKE clause of a raw DB::select and returns the result as JSON, giving an in-band UNION/error-based extraction channel.
keyword=%' UNION SELECT id,CONCAT(email,0x3a,password),3 FROM users-- and reads credentials from the JSON.In-band UNION extraction of any table (PII in signups, credentials, offers) returned directly in the JSON response. Requires only a low-privilege authenticated session (obtainable via ALD-03).
DB::select('... WHERE venue_title LIKE ? ...', ['%'.$seacrh.'%']) or use the Query Builder; escape LIKE wildcards.Confirmed at FoodOffersController.php:1298-1300. CVSS adjusted to 7.6 (A:N — read/write but no direct availability impact in this query shape).
venueOffers concatenates request vid into a raw DB::select in an unquoted numeric context, so no quote-breakout is needed. Injected rows are iterated and reflected into HTML output, enabling UNION extraction and second-order XSS.
vid=0 UNION SELECT id,CONCAT(email,0x3a,password),offer_usage FROM signups-- and reads PII.Arbitrary DB read via UNION/boolean/time-based injection; disclosure of all DB contents including PII and credentials. Low-privilege authenticated session required.
DB::select('... WHERE restaurant_name = ? AND offer_status = ? ...', [(int)$vid,'Draft']) or use Eloquent.Confirmed at VenuesController.php:403-404.
listCategoryVenues concatenates request cid into a raw DB::select in an unquoted numeric context with no validation; rows are reflected as JSON, a clean in-band channel.
cid=0 UNION SELECT id,CONCAT(name,0x3a,email,0x3a,mobile_number) FROM signups-- and reads PII from the JSON.In-band UNION extraction of any table returned in JSON, including signups PII and credentials. Low-privilege authenticated session required.
DB::select('... WHERE category_id = ? ...', [(int)$category]) or Query Builder.Confirmed at AuditController.php:78-88.
userActionHistory concatenates request id into a raw DB::select in an unquoted numeric context. SELECT * plus downstream iteration makes UNION column-matching straightforward.
id=0 UNION SELECT 1,email,password,... FROM users-- to extract credentials.Arbitrary DB read via UNION/boolean/time-based injection, disclosing PII and credentials. Low-privilege authenticated session required.
DB::select('SELECT * FROM users_actions where user_id = ?', [(int)$id]) or Eloquent.Confirmed at AdminController.php:975-976.
Three phpinfo() scripts and two committed error_log files exist; the .htaccess rewrite serves existing files verbatim. APP_DEBUG=true in a production env yields verbose Laravel error pages.
/info.php to dump PHP config/env and /error_log to read absolute paths and the cPanel account, then chains to the Ignition RCE given APP_DEBUG=true.phpinfo() discloses full PHP configuration, paths, and environment (which on cPanel can include secrets) — a complete recon map. Committed logs add filesystem layout and the cPanel account name; APP_DEBUG=true adds stack traces and is the precondition for the Ignition RCE (ALD-07).
info.php/phpinfo.php/public/info.php and both error_log files from the repo and any live host. Set APP_DEBUG=false outside local. Configure the web server to deny dotfiles and *.log.Confirmed all three phpinfo files and APP_DEBUG=true. Overlaps ALD-07/ALD-11; kept distinct as the info-exposure cluster.
Numerous sensitive admin operations are GET routes; Laravel's CSRF middleware never inspects GET, and the session cookie has no SameSite restriction, so it is sent on cross-site GETs. An attacker page can force a logged-in admin's browser to perform these actions via <img> or auto-followed links.
<img src="https://host/admin/blockORsuspend?...">; the browser sends the session cookie cross-site and the action executes.An authenticated admin who visits an attacker page can be silently made to approve/decline accounts, block/suspend users, delete offers/codes, reset users, and approve venues — integrity/availability impact without consent.
same_site to 'lax'/'strict' and SESSION_SECURE_COOKIE=true. Validate Origin/Referer on sensitive actions.Confirmed the GET routes in admin.php and same_site=null/secure=false in config/session.php. Realistic only against an authenticated admin (UI:R).
Stock Laravel password reset with no trusted-host pin and APP_URL=localhost: the framework derives reset-email URLs from the incoming Host header. With no host allowlist it accepts an arbitrary Host and emits reset links pointing to it.
Host: evil.com; the admin receives a reset link to evil.com and, if clicked, the token is captured by the attacker.An attacker who triggers a reset for a victim with a forged Host can produce a reset email whose link points to attacker-controlled host; if the victim clicks, the reset token leaks, enabling account (including admin) takeover. Also enables cache poisoning of host-derived links.
APP_URL to the canonical https domain and generate reset links from config, not the request Host. Keep $proxies tightly scoped.Likely (not confirmed): TrustProxies $headers is the broad ALL set BUT $proxies is null, so X-Forwarded-Host is NOT trusted by default — exploitation relies on the Host header path, which is real for stock reset with no TrustHosts. AC:H/UI:R reflects the click + Host-control requirement.
The committed production env sets APP_DEBUG=true, so Laravel renders Ignition/Whoops error pages with full stack traces, env vars (including the live DB/SMTP passwords in this same env), and paths on any unhandled exception — and satisfies the CVE-2021-3129 RCE precondition.
Unauthenticated disclosure of secrets, source paths, and stack traces on any error; with the EOL Ignition version, unauthenticated RCE (CVE-2021-3129).
APP_DEBUG=false in all non-local environments. Remove facade/ignition from production or patch; ideally decommission the EOL stack. Purge committed env files and rotate secrets.Confirmed. Distinct from ALD-07 (the dependency vuln) and ALD-21 (the info-exposure cluster); this is the misconfiguration itself. CVSS 7.2 (info-disclosure with debug, RCE tracked separately in ALD-07).
The app uses non-cryptographic primitives as authorization tokens: daily offer access keyed on sha1(today's date) with no secret (publicly computable), the literal 'admin' as an admin flag in a URL segment, base64('prive') as a privilege gate, and default-salt Hashids (publicly reversible). Upload filenames use md5(time()).
sha1('Y-m-d') for today and supplies it as the offer access token, and base64('prive')=cHJpdmU= to reach prive-tier offers — all unauthenticated.Unauthenticated authorization bypass: forge sha1(date) to view restricted offer pages, set segment=admin to reach the admin-scoped query branch, supply base64('prive') for prive-tier offers. Default-salt Hashids enables ID enumeration/IDOR; predictable upload names allow guessing/overwriting.
sha1(date) gates with server-side authorization tied to authenticated identity, or HMAC with a secret key + expiry. Never use URL literals or base64 markers for authorization. Configure Hashids with a per-app secret salt. Generate upload filenames with random_bytes()/Str::random().Confirmed sha1(date) at VenueOfferController.php:113-115, base64('prive')/'admin' gates in OfferController/VenueOfferController, no-salt Hashids, and md5(time()) filename. OWASP recategorized to A07 (auth failures) as the core issue is weak authn/authz tokens, not pure crypto.
In the unauthenticated registerVendor handler, the client-supplied location_file_path is concatenated into public_path() for both source and destination of rename() with no basename()/realpath()/'..' filtering.
location_file_path=../../public/shell.php to relocate it to a web-executable path.Arbitrary file move/overwrite within (and potentially outside) the web root by an unauthenticated attacker — defacement, overwriting application files, or relocating an uploaded file to a web-executable path as a step toward RCE. High integrity impact.
basename() and validate against the md5().ext allow-list produced by the upload step. Reject any value with path separators or '..'. Resolve and confirm both source and destination stay inside the intended directory via realpath() prefix checks before rename().Confirmed at VendorSignupController.php:148-157, unauthenticated route in web.php:143. CVSS A set to N (move/overwrite is integrity, not direct availability); requires a pre-staged temp file so practical RCE is a chain.
The chat-agent area mixes three strategies: a custom middleware that only checks a session-key's presence, the proper auth:chat_agent guard on some routes, and no protection on getAjaxOfferDetails (line 38). The session-flag check is weaker than guard-based auth.
GET /chat_agent/getAjaxOfferDetails directly without any session and retrieves pending-offer details.Under-authenticated access to chat-agent offer data via the unprotected getAjaxOfferDetails endpoint, and a fragile model prone to gaps as routes are added.
auth:chat_agent consistently to ALL chat_agent routes including getAjaxOfferDetails. Add Authenticate to the 'chat_agent' middleware group. Replace the session-key presence check with Auth::guard('chat_agent')->check().Confirmed: chat_agent.php:38 has no middleware; chatAgentAuthValidate only checks session::has(). Impact depends on what getAjaxOfferDetails returns — reads as a confidentiality issue.
The session cookie has no SameSite attribute and is not Secure by default. SameSite=null sends the cookie on cross-site requests (enabling the GET-based CSRF of ALD-22); Secure=false allows transmission over plaintext HTTP.
Facilitates CSRF (cookie attached cross-site) and session cookie interception over HTTP, contributing to session hijacking.
same_site to 'lax' (or 'strict' for admin) and SESSION_SECURE_COOKIE=true; enforce HTTPS with HSTS. Consider session.encrypt=true.Confirmed all three values in config/session.php. Largely an amplifier for ALD-22.
A public GET endpoint invokes Artisan queue:work synchronously inside the web request, exposing internal operational functionality and enabling worker exhaustion.
GET /run_queue to drive synchronous queue processing and exhaust workers.Unauthenticated control over queue processing and a low-effort DoS vector (synchronous long-running jobs, including the 3600s-timeout CreatePdfJob, tie up PHP-FPM workers).
Confirmed at routes/web.php:105-108.
allow_url_include=On permits remote URL inclusion, amplifying any file-inclusion/SSRF sink. The app emits no security response headers and configures no HTTPS/HSTS; enable_dl=On further weakens the runtime.
allow_url_include lets the attacker include a remote PHP payload; absent CSP/X-Frame-Options, served pages are clickjackable.Increases blast radius of inclusion/SSRF bugs (ALD-05) and exposes users to clickjacking, MIME-sniffing, and protocol downgrade/MITM. Low standalone severity.
allow_url_include=Off and enable_dl=Off; keep allow_url_fopen=Off unless required. Add CSP, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, and HSTS via middleware or web server. Enforce HTTPS and set a correct APP_URL.Confirmed php.ini directives and absence of security headers.
Multiple public controllers build a whereRaw INTERVAL fragment by concatenating $offer->avail_days, read from venues.avail_days rather than parameterized. The source is currently a DB column, but no store path enforces strict integer validation, so the trust boundary is fragile.
If avail_days ever becomes attacker-influenceable, a stored payload would execute in the INTERVAL clause of these public queries (boolean/time-based blind SQLi on unauthenticated endpoints). Currently low/theoretical because the value is DB-managed.
whereRaw('... INTERVAL ? DAY ...', [(int)$offer->avail_days, Carbon::now()]) and enforce strict integer validation/column typing wherever avail_days is written.Confirmed concatenation at OfferController.php:220 and the DB-sourced origin; theoretical because no current write path injects request data into avail_days.
The Instagram validation rule builds a cURL request from unsanitized user input with TLS verification disabled and redirect-following enabled. If wired into a validator, crafted input plus follow-redirects could coerce server-side requests; disabled TLS verification removes a defense. The rule is not currently referenced, so exploitability today is limited.
If connected to a form: partial SSRF / outbound request control and MITM exposure. Currently dormant, low immediate risk.
^[A-Za-z0-9._]{1,30}$ before use, re-enable CURLOPT_SSL_VERIFYPEER, disable CURLOPT_FOLLOWLOCATION (or bound + re-validate each hop), and remove the dead die()/echo statements. Delete the unused getphoto() helper.Confirmed Instagram.php contents and that the rule is not wired in; remains theoretical/dormant. Also note the rule has die()/echo debug statements that would break validation in practice.
development-alist (cPanel accounts parhaman / frinkae, plus demo.alist.ae / dev.alist.ae DNS) still serves this code. If yes, take it offline today (closes ALD-01/03/05/07 exposure).info@alist.ae (revoke app passwords, enable 2FA), and regenerate the Laravel APP_KEY (ALD-06)._bkp set (ALD-13). Rotate the embedded parhamandco app's APP_KEY + Mailtrap creds (ALD-10).admin@parhamandco.com credential whose bcrypt hash leaked, and handle the leaked signup PII per data-breach policy (ALD-14).APP_DEBUG=false everywhere — it single-handedly closes the CVE-2021-3129 RCE (ALD-07/24).Authenticate to the 'admin' middleware group and an adminAuthValidate middleware to the admin route group; introduce a real admin guard/role and remove Auth::routes() from inside /admin (ALD-01/02/03).DB::select sink (UsersPreviews, FoodOffers, Venues, Audit, Admin controllers) with bound placeholders and integer casts (ALD-04/17/18/19/20).isRemoteEnabled=false in CreatePdfJob and stop rendering user HTML via {!! !!} (ALD-05). Set allow_url_fopen/allow_url_include=Off (ALD-30)..env_4-May-2020, .config.json, config/thirdparty.php_bkp, parhamandco.sql, parhamandco.zip, info.php/phpinfo.php/public/info.php, error_log) and add <FilesMatch> deny rules (ALD-10/11/14/21).alist-portal (Laravel 11 / PHP 8.2) rather than patching the EOL stack (ALD-09/12).git filter-repo / BFG, then add a tightened .gitignore (.env*, *.sql, *.zip, *.config.json).same_site=lax and SESSION_SECURE_COOKIE=true (ALD-22/28).APP_URL, and remove the /run_queue route (ALD-23/29).auth:chat_agent consistently across the chat-agent routes and replace the session-key presence check with a guard (ALD-27).hooks.slack.com URLs, JWTs, AIza keys, base64 APP_KEYs).X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, and HSTS; enforce HTTPS (ALD-30).random_bytes()/Str::random() (ALD-25).avail_days in the whereRaw INTERVAL clauses and fix the dormant insecure-cURL Instagram rule before any reuse (ALD-31/32).laravel/framework ^6.2 vs current 11.x; guzzlehttp/guzzle ^6.5 vs 7.x; sentry/sentry-laravel ^1.9 vs 4.x; jdavidbakr/mail-tracker 3.* vs 7.x. No upgrade is realistic — consolidate onto alist-portal.*_bkp, *_bkp_live), Notifications_2/, routes/web_15-May-2020.php, __BACKUPS/, parhamandco.zip, parhamandco.sql.app/Http/Controllers/OfferController.php and the Admin/FoodOffersController.php family are likely the largest, judging by the presence of _bkp_live variants — almost always a sign of fat-controller patterns, and the same files that host the raw-SQL and weak-token findings above.routes/api.php is only 15 lines, so this codebase was almost entirely server-rendered (Blade), not an API backend, despite the "Backend" label in Bitbucket.# You almost certainly should NOT bring this up. PHP 7.2 is EOL.
# If you must, do it on an isolated VM with no network egress.
# 1. Install PHP 7.2 (Homebrew no longer ships it — use shivammathur/php tap or Docker php:7.2-fpm)
brew tap shivammathur/php
brew install shivammathur/php/php@7.2
# 2. Install Composer deps
composer install --ignore-platform-reqs
# 3. Configure env
cp .env.example .env
php artisan key:generate
# Edit .env: set DB_DATABASE / DB_USERNAME / DB_PASSWORD to a LOCAL throwaway DB
# Set APP_DEBUG=false unless you specifically need Ignition
# 4. Migrate
php artisan migrate
# Do NOT run db:seed blindly — see P2 finding about step*.php scripts
# 5. Serve
php artisan serve
# 6. Queue worker (optional, see a-list-supervisorconf.config)
php artisan queue:listen --tries=2 --timeout=7200
APP_KEY, APP_ENV, APP_DEBUG, APP_URLDB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORDMAIL_DRIVER, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTIONREDIS_HOST, REDIS_PORT, REDIS_PASSWORD (only if you switch caches/queues off file/sync)AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_BUCKET (likely unused — empty in .env.example)PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_CLUSTER.config.json (clientID, clientSecret, developerKey, refreshToken) — should be moved to env vars and the file purged (ALD-08).Historical deployment was on cPanel hosting. Two distinct cPanel accounts appear in committed artifacts: frinkae (per error_log paths) and parhaman (per a-list-supervisorconf.config). Both targeted a directory named Development-Alist / development-alist. .htaccess rewrites every URL through /public/index.php, which is the standard "Laravel without docroot remap" cPanel pattern — and the same !-f rewrite is what makes the committed secret/diagnostic files web-reachable (ALD-11). .user.ini / php.ini override memory_limit to 6 GB and upload_max_filesize to 4 GB — clearly tuned for a specific upload feature. No CI pipeline is committed (no bitbucket-pipelines.yml, no GitHub Actions, no Jenkinsfile). Releases appear to have been manual pushes ("code pushed to live repository", commit dcf20e9 on 2020-10-30).
alist-portal, which has 5 years and ~10 framework-major versions of divergent history.demo.alist.ae / dev.alist.ae or any cPanel account named parhaman / frinkae still resolving. While it is alive, the unauthenticated admin panel (ALD-01/03) and Ignition RCE (ALD-07) are live.middleware('auth') on the default guard all fail to gate it, and anyone can self-register straight to admin. Do not assume /admin is protected.app/ (Laravel 6 convention), not app/Models/. Don't reflexively "fix" that — it requires updating every use statement..php_bkp, .php_bkp_live, dated like web_15-May-2020.php, or sitting under __BACKUPS/ is dead code. Don't read it expecting it to match the live behaviour.app/Notifications_2/ exists next to app/Notifications/. It looks like a manual copy taken before a refactor that never happened. Use Notifications/.database/seeds/step*.php are one-shot historical data fixes, not idempotent seeders. Do not run php artisan db:seed blindly against any DB you care about.routes/api.php is only 15 lines. Despite the repo description ("A-List Demo Backend"), this is a server-rendered Blade app — not an API tier..htaccess vs .htaccess11: only .htaccess is loaded by Apache. The 11 variant is a leftover. Same story for info.php at the root vs public/info.php — and all of them should be deleted regardless (ALD-21).memory_limit=6144M and post_max_size=4096M in .user.ini/php.ini/.htaccess were tuned for whatever bulk import this app did. Don't replicate those settings on modern hosts without understanding why. Note allow_url_include=On there too (ALD-30)..git alone is 144 MB; parhamandco.zip is 24 MB. Shallow-clone where possible — and remember the zip embeds a second app's live secrets (ALD-10).