type !== 'domain') { throw new RunnerException('crt.sh only supports "domain" targets.'); } $response = Http::timeout((int) config('osint.run_timeout')) ->get('https://crt.sh/', [ 'q' => $target->value, 'output' => 'json', ]); if (! $response->successful()) { throw new RunnerException('crt.sh request failed with status '.$response->status().'.'); } // crt.sh returns an empty body (not valid JSON) when there are no matches. $certificates = $response->json() ?? []; $subdomains = collect($certificates) ->flatMap(fn (array $cert) => explode("\n", $cert['name_value'] ?? '')) ->map(fn (string $name) => strtolower(trim($name))) ->filter() ->unique() ->sort() ->values(); $summary = $subdomains->isNotEmpty() ? sprintf('Found %d unique subdomain%s in certificate logs.', $subdomains->count(), $subdomains->count() === 1 ? '' : 's') : 'No certificates found.'; return new RunnerResult(raw: ['subdomains' => $subdomains->all()], summary: $summary); } }