Area: mobieusMarket / BBS (audit p3) · Surface: mobieusMarket BBS /bbs-directory/connect-token (premium_id) + /bbs/{slug}/connect · Dimension: security · Severity: minor
OWASP A10 SSRF (defence-in-depth gap / inconsistency). The community connect path correctly refuses internal/link-local/metadata hosts before handing host:port to the in-browser terminal, but the premium path (connectToken premium_id branch and /bbs/{slug}/connect) does not, even though premium telnet_host values can originate from unvalidated user submissions promoted by an admin. A super-admin promoting a community entry pointing at 169.254.169.254 or an RFC1918 address would create a premium listing that any authenticated user can target the telnet proxy at. The validation already exists and is applied on the sibling branches; the premium branch and GET connect are simply missing the same call.
Evidence
BbsListingController.php:684-700 (premium branch of connectToken): returns `'host' => $listing['telnet_host']` directly from bbs_listings with NO isPublicHost check. Contrast the community branch at lines 702-743 which DOES call `if (!\App\Services\UrlValidator::isPublicHost($host, $reason)) { $this->json(['error' => ...], 400); }` (line 732). The premium host can be user-influenced: promoteToFeatured (BbsListingController.php:145-259) copies a USER-SUBMITTED bbs_directory.url (created via BbsDirectoryController@submit, BbsDirectoryController.php:25-62, which performs only a scheme allowlist, no host/IP validation) into bbs_listings.telnet_host (INSERT at lines 199-216) without ever calling isPublicHost. The GET connect route (BbsListingController.php:641-668) likewise emits telnet_host into the template data-host attribute (templates/bbs/connect.php:24) with no SSRF check. Note capturePreview (AdminBbsListingController.php:178-185) DOES guard, proving the codebase considers this host attacker-reachable.
Suggested fix. Apply UrlValidator::isPublicHost() to telnet_host in the connectToken premium_id branch (BbsListingController.php ~line 692) and in connect() before rendering, mirroring the community branch at line 732. Additionally run isPublicHost on the parsed host inside promoteToFeatured before inserting into bbs_listings so private hosts can never be promoted. (The ultimate outbound socket should also validate at the /ws/bbs-telnet proxy, which is out of this repo.)
Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.
Patrick Bass
@mobieus