<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sandro</title>
    <description>The latest articles on DEV Community by Sandro (@xil).</description>
    <link>https://dev.to/xil</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162961%2F396c1c7a-e5f6-44a5-873b-ee0685d38e2b.png</url>
      <title>DEV Community: Sandro</title>
      <link>https://dev.to/xil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xil"/>
    <language>en</language>
    <item>
      <title>I Built Bug Hunter: A Self-Hosted Full-Stack Testing Tool for Web Apps and APIs</title>
      <dc:creator>Sandro</dc:creator>
      <pubDate>Wed, 15 Jul 2026 13:24:52 +0000</pubDate>
      <link>https://dev.to/xil/i-built-universal-bug-hunter-a-self-hosted-full-stack-testing-tool-for-web-apps-and-apis-4e1o</link>
      <guid>https://dev.to/xil/i-built-universal-bug-hunter-a-self-hosted-full-stack-testing-tool-for-web-apps-and-apis-4e1o</guid>
      <description>&lt;p&gt;Modern web application failures rarely happen in one isolated place.&lt;/p&gt;

&lt;p&gt;A user clicks a button, the frontend sends an API request, the backend returns an unexpected response, and the interface remains stuck in a loading state.&lt;/p&gt;

&lt;p&gt;A health check may still be green. A unit test may still pass. The visible symptom may appear in the browser, while the actual cause is somewhere between the frontend, API, runtime environment, and application configuration.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Universal Bug Hunter&lt;/strong&gt; to make those failures easier to detect, investigate, reproduce, and document.&lt;/p&gt;

&lt;p&gt;It is a self-hosted testing tool that combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browser testing with Playwright and Chromium,&lt;/li&gt;
&lt;li&gt;direct API smoke testing,&lt;/li&gt;
&lt;li&gt;OpenAPI discovery,&lt;/li&gt;
&lt;li&gt;optional AI-assisted test proposal generation,&lt;/li&gt;
&lt;li&gt;deterministic bug detectors,&lt;/li&gt;
&lt;li&gt;runtime evidence collection,&lt;/li&gt;
&lt;li&gt;finding reproduction,&lt;/li&gt;
&lt;li&gt;static analysis integrations,&lt;/li&gt;
&lt;li&gt;and HTML/JSON reporting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to replace QA engineers, security testers, code review, or existing test suites.&lt;/p&gt;

&lt;p&gt;The goal is more practical:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Execute realistic application flows, preserve useful evidence, and make failures easier to understand and reproduce.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;Many automated checks answer only one narrow question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did the endpoint return HTTP 200?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is useful, but it does not tell you what happened after the page loaded.&lt;/p&gt;

&lt;p&gt;It does not tell you whether:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the browser logged a JavaScript error,&lt;/li&gt;
&lt;li&gt;an API call returned HTTP 500,&lt;/li&gt;
&lt;li&gt;the interface became stuck,&lt;/li&gt;
&lt;li&gt;a click produced no visible state change,&lt;/li&gt;
&lt;li&gt;the page overflowed horizontally,&lt;/li&gt;
&lt;li&gt;a loading indicator never disappeared,&lt;/li&gt;
&lt;li&gt;a test failed because of the application,&lt;/li&gt;
&lt;li&gt;or the testing engine itself failed operationally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted one workflow that could test a web application from the outside, like a real user, while still collecting enough technical context for a developer or operator to investigate the result.&lt;/p&gt;

&lt;p&gt;That idea became Universal Bug Hunter.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Universal Bug Hunter does
&lt;/h2&gt;

&lt;p&gt;The current workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create project
→ Discover routes
→ Review and approve routes
→ Generate optional AI test proposals
→ Review and approve proposals
→ Compile proposals into scenarios
→ Execute browser and API scenarios
→ Detect findings
→ Reproduce supported findings
→ Generate HTML and JSON reports
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The approval steps are intentional.&lt;/p&gt;

&lt;p&gt;Discovery does not automatically execute everything it finds.&lt;/p&gt;

&lt;p&gt;AI does not approve or run its own proposals.&lt;/p&gt;

&lt;p&gt;Compilation creates scenario files, but it does not automatically launch the browser.&lt;/p&gt;

&lt;p&gt;The operator remains in control of what is allowed to run.&lt;/p&gt;




&lt;h2&gt;
  
  
  Browser testing with Playwright
&lt;/h2&gt;

&lt;p&gt;Universal Bug Hunter uses Chromium through Playwright to test an application as a user would experience it.&lt;/p&gt;

&lt;p&gt;Browser scenarios can navigate through the application, interact with visible elements, verify UI state, and capture screenshots.&lt;/p&gt;

&lt;p&gt;A simple scenario can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;navigate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/login&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;waitForVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Username&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;captureScreenshot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;login-page&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During execution, Bug Hunter can collect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browser console messages,&lt;/li&gt;
&lt;li&gt;uncaught page errors,&lt;/li&gt;
&lt;li&gt;failed network requests,&lt;/li&gt;
&lt;li&gt;HTTP 4xx and 5xx responses,&lt;/li&gt;
&lt;li&gt;screenshots,&lt;/li&gt;
&lt;li&gt;DOM snapshots,&lt;/li&gt;
&lt;li&gt;navigation information,&lt;/li&gt;
&lt;li&gt;and other runtime evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current deterministic detector set includes checks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;console-error&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;page-error&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;failed-request&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http-error&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blank-page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;horizontal-overflow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stuck-loader&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;no-state-change&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These detectors do not depend on an LLM. They evaluate collected evidence using predictable rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  Direct API testing
&lt;/h2&gt;

&lt;p&gt;Browser testing only covers backend requests that are actually triggered by the frontend.&lt;/p&gt;

&lt;p&gt;To improve backend coverage, I added direct HTTP scenarios.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/ready&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertHttpStatus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A POST scenario can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpPost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/auth/login&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
      &lt;span class="na"&gt;jsonBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertHttpStatus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browser scenarios and HTTP-only scenarios use separate execution paths.&lt;/p&gt;

&lt;p&gt;A composite orchestrator can still run both types as part of the same batch.&lt;/p&gt;

&lt;p&gt;This keeps browser execution and direct API execution clearly separated while allowing them to contribute to the same project-level test workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  OpenAPI discovery and API smoke generation
&lt;/h2&gt;

&lt;p&gt;For applications that expose an OpenAPI specification, Bug Hunter can import the specification and build an inventory of API operations.&lt;/p&gt;

&lt;p&gt;The basic flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OpenAPI specification
→ operation discovery
→ generated API smoke scenarios
→ scenario approval
→ execution
→ report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current generator supports basic GET and POST smoke coverage.&lt;/p&gt;

&lt;p&gt;For example, an imported API specification can produce scenarios for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /health
GET /ready
POST /api/auth/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is intentionally conservative.&lt;/p&gt;

&lt;p&gt;The current version does not yet attempt to generate complex destructive requests automatically.&lt;/p&gt;

&lt;p&gt;Support for OpenAPI parameters, authentication profiles, request body generation, response schema validation, and negative API testing is planned for future versions.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI-assisted exploration with human approval
&lt;/h2&gt;

&lt;p&gt;AI exploration is optional.&lt;/p&gt;

&lt;p&gt;When enabled, an LLM receives a controlled representation of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;approved routes,&lt;/li&gt;
&lt;li&gt;discovered interactions,&lt;/li&gt;
&lt;li&gt;existing scenarios,&lt;/li&gt;
&lt;li&gt;and detected coverage gaps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can propose read-only test scenarios using a restricted action set such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;navigate,&lt;/li&gt;
&lt;li&gt;click,&lt;/li&gt;
&lt;li&gt;assert visible,&lt;/li&gt;
&lt;li&gt;assert URL,&lt;/li&gt;
&lt;li&gt;capture screenshot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every proposal passes through a deterministic safety pipeline.&lt;/p&gt;

&lt;p&gt;A proposal must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;target an approved route,&lt;/li&gt;
&lt;li&gt;use only permitted actions,&lt;/li&gt;
&lt;li&gt;remain read-only,&lt;/li&gt;
&lt;li&gt;stay within configured step limits,&lt;/li&gt;
&lt;li&gt;avoid credentials and sensitive values,&lt;/li&gt;
&lt;li&gt;and conform to a strict schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Passing this validation does not mean the proposal is automatically approved.&lt;/p&gt;

&lt;p&gt;The workflow remains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI-generated
≠ safe by default

Safety accepted
≠ human approved

Human approved
≠ automatically executed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operator reviews each accepted proposal and decides whether it should be approved, rejected, or compiled into a scenario.&lt;/p&gt;




&lt;h2&gt;
  
  
  Findings, evidence, and reproduction
&lt;/h2&gt;

&lt;p&gt;A useful bug report should not only say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A request failed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should help answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which scenario triggered the problem?&lt;/li&gt;
&lt;li&gt;Which route was active?&lt;/li&gt;
&lt;li&gt;Which action happened before the failure?&lt;/li&gt;
&lt;li&gt;What did the browser log?&lt;/li&gt;
&lt;li&gt;Which request failed?&lt;/li&gt;
&lt;li&gt;Was the behavior reproduced?&lt;/li&gt;
&lt;li&gt;Is there a screenshot?&lt;/li&gt;
&lt;li&gt;Is there a DOM snapshot?&lt;/li&gt;
&lt;li&gt;Is the finding eligible for reporting?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bug Hunter stores evidence separately from project configuration.&lt;/p&gt;

&lt;p&gt;A typical run can contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;batch-report.json
batch-report.html
batch-state.json
runs/
  run-summary.json
  findings.json
  evidence/
  screenshots/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When supported, a finding can be replayed in a fresh browser session.&lt;/p&gt;

&lt;p&gt;This helps distinguish a reproducible application issue from one-time browser or environment noise.&lt;/p&gt;




&lt;h2&gt;
  
  
  Execution success is not the same as a passing test result
&lt;/h2&gt;

&lt;p&gt;This distinction became one of the most important parts of the system.&lt;/p&gt;

&lt;p&gt;A job can complete successfully from an infrastructure perspective while the tested application still produces findings.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Execution job: completed
Scenarios executed: 6
Passed: 3
With findings: 3
Operational failures: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the execution engine completed,&lt;/li&gt;
&lt;li&gt;all six scenarios were executed,&lt;/li&gt;
&lt;li&gt;three scenarios produced no findings,&lt;/li&gt;
&lt;li&gt;three scenarios produced detector findings,&lt;/li&gt;
&lt;li&gt;and the runner itself did not fail operationally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is different from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Operational failures: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An operational failure may indicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the browser could not start,&lt;/li&gt;
&lt;li&gt;navigation timed out,&lt;/li&gt;
&lt;li&gt;a required element could not be found,&lt;/li&gt;
&lt;li&gt;the scenario could not complete,&lt;/li&gt;
&lt;li&gt;or the runtime environment failed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am continuing to improve this distinction in the operator dashboard so that &lt;code&gt;Completed&lt;/code&gt;, &lt;code&gt;Passed&lt;/code&gt;, &lt;code&gt;With findings&lt;/code&gt;, and &lt;code&gt;Operational failure&lt;/code&gt; cannot be confused with each other.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing localhost applications from Docker
&lt;/h2&gt;

&lt;p&gt;One of my main requirements was testing applications before they are publicly deployed.&lt;/p&gt;

&lt;p&gt;Bug Hunter can run locally through Docker while testing another application that is running:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;directly on the Windows host,&lt;/li&gt;
&lt;li&gt;inside another Docker Compose service,&lt;/li&gt;
&lt;li&gt;on a private development address,&lt;/li&gt;
&lt;li&gt;or on a regular staging URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From inside a container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;refers to that container itself.&lt;/p&gt;

&lt;p&gt;For an application running directly on the Windows host, Bug Hunter uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://host.docker.internal:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A local target can be configured like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://host.docker.internal:3000&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
  &lt;span class="na"&gt;allowedDomains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;host.docker.internal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A full-stack project can define separate frontend and API targets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fullstack&lt;/span&gt;

&lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://host.docker.internal:3000&lt;/span&gt;

  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://host.docker.internal:8787&lt;/span&gt;
    &lt;span class="na"&gt;healthPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/ready&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Private and loopback targets are not enabled globally.&lt;/p&gt;

&lt;p&gt;They must be explicitly allowed through the local environment and network policy configuration.&lt;/p&gt;

&lt;p&gt;The same allowlist logic is applied to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browser navigation,&lt;/li&gt;
&lt;li&gt;redirects,&lt;/li&gt;
&lt;li&gt;direct HTTP scenarios,&lt;/li&gt;
&lt;li&gt;and OpenAPI retrieval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This preserves the SSRF protection while still allowing intentional localhost testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Static analysis integrations
&lt;/h2&gt;

&lt;p&gt;Bug Hunter also includes a static analysis layer with provider adapters for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semgrep&lt;/strong&gt; for SAST,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trivy&lt;/strong&gt; for dependency and filesystem analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The static analysis command writes normalized results into the project workspace.&lt;/p&gt;

&lt;p&gt;If a configured tool is not installed, the pipeline reports that the provider is unavailable instead of crashing the entire workflow.&lt;/p&gt;

&lt;p&gt;This is still an early integration.&lt;/p&gt;

&lt;p&gt;The goal is not to replace dedicated Semgrep or Trivy workflows.&lt;/p&gt;

&lt;p&gt;The longer-term goal is to present dynamic browser findings, API findings, dependency findings, and static analysis results within the same project context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Universal Bug Hunter is a TypeScript monorepo built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 22&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;pnpm workspaces&lt;/li&gt;
&lt;li&gt;Fastify&lt;/li&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Playwright&lt;/li&gt;
&lt;li&gt;Chromium&lt;/li&gt;
&lt;li&gt;TanStack Query&lt;/li&gt;
&lt;li&gt;Zod&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;li&gt;OpenAI as an optional exploration provider&lt;/li&gt;
&lt;li&gt;Semgrep&lt;/li&gt;
&lt;li&gt;Trivy&lt;/li&gt;
&lt;li&gt;HTML and JSON reporters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system is divided into focused packages for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;core domain models,&lt;/li&gt;
&lt;li&gt;configuration and validation,&lt;/li&gt;
&lt;li&gt;browser execution,&lt;/li&gt;
&lt;li&gt;direct HTTP execution,&lt;/li&gt;
&lt;li&gt;route discovery,&lt;/li&gt;
&lt;li&gt;OpenAPI discovery,&lt;/li&gt;
&lt;li&gt;AI exploration,&lt;/li&gt;
&lt;li&gt;evidence storage,&lt;/li&gt;
&lt;li&gt;deterministic detectors,&lt;/li&gt;
&lt;li&gt;finding reproduction,&lt;/li&gt;
&lt;li&gt;scenario execution,&lt;/li&gt;
&lt;li&gt;reporting,&lt;/li&gt;
&lt;li&gt;API services,&lt;/li&gt;
&lt;li&gt;CLI commands,&lt;/li&gt;
&lt;li&gt;and the web operator interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I intentionally avoided placing browser control, filesystem access, AI calls, HTTP testing, reporting, and security policy inside one large service.&lt;/p&gt;

&lt;p&gt;Testing systems become difficult to maintain when every responsibility is tightly coupled to the runner.&lt;/p&gt;




&lt;h2&gt;
  
  
  The operator workflow
&lt;/h2&gt;

&lt;p&gt;The web interface follows the project lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Overview
→ Discovery
→ Exploration
→ Proposals
→ Scenarios
→ Runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operator can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a project,&lt;/li&gt;
&lt;li&gt;start route discovery,&lt;/li&gt;
&lt;li&gt;approve or reject discovered routes,&lt;/li&gt;
&lt;li&gt;start optional AI exploration,&lt;/li&gt;
&lt;li&gt;review proposals,&lt;/li&gt;
&lt;li&gt;approve or reject proposals,&lt;/li&gt;
&lt;li&gt;compile approved proposals,&lt;/li&gt;
&lt;li&gt;run all approved scenarios,&lt;/li&gt;
&lt;li&gt;run selected scenarios,&lt;/li&gt;
&lt;li&gt;inspect execution history,&lt;/li&gt;
&lt;li&gt;review findings,&lt;/li&gt;
&lt;li&gt;and download HTML or JSON reports.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interface is deliberately operator-focused.&lt;/p&gt;

&lt;p&gt;It does not expose target URL changes, browser configuration, credentials, or reporting configuration during scenario execution.&lt;/p&gt;

&lt;p&gt;Those values remain controlled by the project manifest and backend policy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Local verification
&lt;/h2&gt;

&lt;p&gt;I tested the current full-stack workflow in two different ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  Host execution
&lt;/h3&gt;

&lt;p&gt;The first test executed directly from the host against the local web UI and API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Selected: 6
Passed: 6
Operational failures: 0
Exit code: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The batch contained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;three browser smoke scenarios,&lt;/li&gt;
&lt;li&gt;three direct API smoke scenarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker-to-host execution
&lt;/h3&gt;

&lt;p&gt;The second test ran from the Docker API container against the Windows host through &lt;code&gt;host.docker.internal&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Selected: 6
Executed: 6
Passed: 3
With findings: 3
Operational failures: 0
Exit code: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three API scenarios passed.&lt;/p&gt;

&lt;p&gt;The three browser scenarios completed operationally but produced console or network findings.&lt;/p&gt;

&lt;p&gt;This demonstrated an important behavior:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The execution engine can complete correctly while the tested application still produces reportable findings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An exit code of &lt;code&gt;1&lt;/code&gt; does not necessarily mean the testing infrastructure crashed.&lt;/p&gt;

&lt;p&gt;It can mean that relevant findings were detected.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current limitations
&lt;/h2&gt;

&lt;p&gt;Universal Bug Hunter is still evolving.&lt;/p&gt;

&lt;p&gt;The current version has several known limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;job state is stored in memory and is lost after an API restart,&lt;/li&gt;
&lt;li&gt;authentication currently supports one local admin account,&lt;/li&gt;
&lt;li&gt;the execution queue runs inside one Node.js process,&lt;/li&gt;
&lt;li&gt;API smoke generation has limited OpenAPI parameter and body support,&lt;/li&gt;
&lt;li&gt;HTTP-only scenarios do not yet have the same reproduction flow as browser scenarios,&lt;/li&gt;
&lt;li&gt;backend logs and distributed traces are not yet correlated with browser requests,&lt;/li&gt;
&lt;li&gt;static analysis integrations are still basic,&lt;/li&gt;
&lt;li&gt;artifact retention and cleanup need stronger lifecycle controls,&lt;/li&gt;
&lt;li&gt;concurrency and browser resource limits need further hardening,&lt;/li&gt;
&lt;li&gt;and deployment is currently focused on local self-hosting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I prefer being clear about these limitations.&lt;/p&gt;

&lt;p&gt;An automated testing tool should not create false confidence.&lt;/p&gt;

&lt;p&gt;A successful run does not prove that an application has no bugs.&lt;/p&gt;

&lt;p&gt;It only proves that the selected scenarios completed under the tested conditions without producing findings recognized by the enabled detectors.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I am improving next
&lt;/h2&gt;

&lt;p&gt;The next areas I am working on include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;job concurrency and queue limits,&lt;/li&gt;
&lt;li&gt;browser session limits,&lt;/li&gt;
&lt;li&gt;artifact retention and cleanup,&lt;/li&gt;
&lt;li&gt;structured operational logging,&lt;/li&gt;
&lt;li&gt;better runtime status visibility,&lt;/li&gt;
&lt;li&gt;OpenAPI parameter support,&lt;/li&gt;
&lt;li&gt;request body generation,&lt;/li&gt;
&lt;li&gt;authentication profiles for API scenarios,&lt;/li&gt;
&lt;li&gt;negative API test generation,&lt;/li&gt;
&lt;li&gt;response schema assertions,&lt;/li&gt;
&lt;li&gt;backend log and trace correlation,&lt;/li&gt;
&lt;li&gt;and clearer result summaries in the operator dashboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One longer-term goal is to correlate the complete path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser action
→ frontend state
→ API request
→ backend response
→ log or trace
→ one combined finding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That would make Bug Hunter more useful than a collection of disconnected browser, API, and static checks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this project matters to me
&lt;/h2&gt;

&lt;p&gt;I built Universal Bug Hunter as a practical QA automation, DevOps, and DevSecOps project.&lt;/p&gt;

&lt;p&gt;It combines several areas I regularly work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browser automation,&lt;/li&gt;
&lt;li&gt;API testing,&lt;/li&gt;
&lt;li&gt;TypeScript,&lt;/li&gt;
&lt;li&gt;Docker,&lt;/li&gt;
&lt;li&gt;application security,&lt;/li&gt;
&lt;li&gt;evidence collection,&lt;/li&gt;
&lt;li&gt;reporting,&lt;/li&gt;
&lt;li&gt;CI/CD design,&lt;/li&gt;
&lt;li&gt;and system architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most interesting part was not simply making Playwright click through a page.&lt;/p&gt;

&lt;p&gt;The harder questions were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What should the system be allowed to execute?&lt;/li&gt;
&lt;li&gt;How do you prevent AI proposals from bypassing safety rules?&lt;/li&gt;
&lt;li&gt;How do you distinguish a product bug from an environment problem?&lt;/li&gt;
&lt;li&gt;How do you preserve useful evidence without leaking secrets?&lt;/li&gt;
&lt;li&gt;How do you reproduce findings deterministically?&lt;/li&gt;
&lt;li&gt;How do you test localhost applications safely from Docker?&lt;/li&gt;
&lt;li&gt;How do you explain that a job completed even when tests found problems?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those questions shaped the architecture more than the UI itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current status
&lt;/h2&gt;

&lt;p&gt;Universal Bug Hunter currently runs as a local, self-hosted testing environment.&lt;/p&gt;

&lt;p&gt;I am testing it against local applications before considering a public deployment.&lt;/p&gt;

&lt;p&gt;The complete current flow works from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;URL discovery
→ route approval
→ optional AI exploration
→ proposal review
→ scenario compilation
→ browser and API execution
→ findings
→ report download
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am sharing the project to get feedback from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;QA engineers,&lt;/li&gt;
&lt;li&gt;developers,&lt;/li&gt;
&lt;li&gt;DevOps engineers,&lt;/li&gt;
&lt;li&gt;platform engineers,&lt;/li&gt;
&lt;li&gt;and security practitioners.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would especially appreciate feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the workflow is understandable,&lt;/li&gt;
&lt;li&gt;whether findings contain enough evidence,&lt;/li&gt;
&lt;li&gt;whether operational failures and application findings are clearly separated,&lt;/li&gt;
&lt;li&gt;which API checks would be most useful,&lt;/li&gt;
&lt;li&gt;whether the approval workflow feels too strict or appropriately safe,&lt;/li&gt;
&lt;li&gt;and what would make the tool useful in a real development workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Universal Bug Hunter is still a work in progress, but the core idea is already clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find problems through realistic application flows, preserve the evidence, and make the result easier to understand and reproduce.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>I Built PentestScan: A Simple Web &amp; API Security Scanner for Developers and Small Teams</title>
      <dc:creator>Sandro</dc:creator>
      <pubDate>Mon, 18 May 2026 06:30:58 +0000</pubDate>
      <link>https://dev.to/xil/i-built-pentestscan-a-simple-web-api-security-scanner-for-developers-and-small-teams-38km</link>
      <guid>https://dev.to/xil/i-built-pentestscan-a-simple-web-api-security-scanner-for-developers-and-small-teams-38km</guid>
      <description>&lt;p&gt;Building security tools always sounds more impressive than it really is at the beginning.&lt;/p&gt;

&lt;p&gt;In my case, PentestScan started as a practical idea:&lt;br&gt;
I wanted to build a simple Web &amp;amp; API security scanner that could help developers, small teams, and DevOps engineers catch common security issues earlier - before an application reaches production.&lt;/p&gt;

&lt;p&gt;Not as a replacement for professional penetration testing.&lt;br&gt;
Not as a magic “find everything” scanner.&lt;br&gt;
But it is a practical DevSecOps tool that gives fast, understandable feedback.&lt;/p&gt;

&lt;p&gt;The problem I wanted to solve was simple:&lt;/p&gt;

&lt;p&gt;A lot of small teams do not have a dedicated AppSec engineer.&lt;br&gt;
Security reviews often happen too late.&lt;br&gt;
Reports from bigger tools can be too complex, too noisy, or too expensive for early-stage projects.&lt;br&gt;
And developers usually need something direct:&lt;/p&gt;

&lt;p&gt;What is wrong?&lt;br&gt;
Why does it matter?&lt;br&gt;
How can I fix it?&lt;/p&gt;

&lt;p&gt;That is the direction I took with PentestScan.&lt;/p&gt;

&lt;p&gt;What PentestScan does&lt;/p&gt;

&lt;p&gt;PentestScan is a Web &amp;amp; API security scanner focused on practical checks around common security weaknesses.&lt;/p&gt;

&lt;p&gt;The current version is built around:&lt;/p&gt;

&lt;p&gt;Web application scanning&lt;br&gt;
API security testing&lt;br&gt;
OWASP Top 10 related checks&lt;br&gt;
Security headers analysis&lt;br&gt;
JWT and session-related checks&lt;br&gt;
Basic exposure detection&lt;br&gt;
Report generation&lt;br&gt;
DevSecOps-friendly workflow&lt;/p&gt;

&lt;p&gt;The goal is not to overload the user with hundreds of unclear findings.&lt;/p&gt;

&lt;p&gt;The goal is to provide a clean report that helps someone understand the risk and take action.&lt;/p&gt;

&lt;p&gt;Tech stack&lt;/p&gt;

&lt;p&gt;The project is built with a simple and practical stack:&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
FastAPI&lt;br&gt;
Docker&lt;br&gt;
Nginx&lt;br&gt;
HTML reporting&lt;br&gt;
API-first backend structure&lt;br&gt;
Security-focused scanning modules&lt;/p&gt;

&lt;p&gt;I wanted the architecture to stay modular because security tooling can become messy very quickly if everything is placed into one large script.&lt;/p&gt;

&lt;p&gt;So the scanner is organized around separate modules and checks, with the idea that new functionality can be added gradually without breaking the existing structure.&lt;/p&gt;

&lt;p&gt;Why I built it&lt;/p&gt;

&lt;p&gt;I built PentestScan mainly as a hands-on DevSecOps project.&lt;/p&gt;

&lt;p&gt;I wanted to combine several areas that I work with and care about:&lt;/p&gt;

&lt;p&gt;application security&lt;br&gt;
backend development&lt;br&gt;
automation&lt;br&gt;
Linux deployment&lt;br&gt;
Docker-based services&lt;br&gt;
CI/CD security thinking&lt;br&gt;
security reporting&lt;/p&gt;

&lt;p&gt;One thing I learned while building it is that detection is only one part of the problem.&lt;/p&gt;

&lt;p&gt;The harder part is explaining the finding in a useful way.&lt;/p&gt;

&lt;p&gt;A security report should not only say:&lt;/p&gt;

&lt;p&gt;Missing security header detected.&lt;/p&gt;

&lt;p&gt;It should explain:&lt;/p&gt;

&lt;p&gt;what was detected,&lt;br&gt;
why it matters,&lt;br&gt;
how it could be abused,&lt;br&gt;
how serious it is,&lt;br&gt;
and what the developer can do next.&lt;/p&gt;

&lt;p&gt;That became one of the most important ideas behind the project.&lt;/p&gt;

&lt;p&gt;What I am trying to improve&lt;/p&gt;

&lt;p&gt;PentestScan is still evolving.&lt;/p&gt;

&lt;p&gt;Some of the things I am working on or planning to improve are:&lt;/p&gt;

&lt;p&gt;better API scanning&lt;br&gt;
cleaner report structure&lt;br&gt;
more contextual findings&lt;br&gt;
CI/CD integration&lt;br&gt;
better severity scoring&lt;br&gt;
improved attack-path style explanations&lt;br&gt;
more useful remediation guidance&lt;br&gt;
public sample reports&lt;/p&gt;

&lt;p&gt;I am also trying to keep the tool realistic.&lt;/p&gt;

&lt;p&gt;Security scanners can easily create false confidence.&lt;br&gt;
Just because a scanner does not find something does not mean the application is secure.&lt;/p&gt;

&lt;p&gt;So I see PentestScan as a first security layer - something that can help teams catch obvious and common issues earlier, not as a full replacement for manual testing.&lt;/p&gt;

&lt;p&gt;Current version&lt;/p&gt;

&lt;p&gt;The project is currently available for free here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pentestscan.app/" rel="noopener noreferrer"&gt;https://pentestscan.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before trying the scanner, you can also check a public sample report:&lt;/p&gt;

&lt;p&gt;Sample vulnerability report:&lt;br&gt;&lt;br&gt;
&lt;a href="https://pentestscan.app/api/v1/public/marketing/vulnerability_report.html" rel="noopener noreferrer"&gt;https://pentestscan.app/api/v1/public/marketing/vulnerability_report.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am sharing PentestScan publicly to get feedback from developers, DevOps engineers, and security people.&lt;/p&gt;

&lt;p&gt;I would especially appreciate feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;report structure and clarity,&lt;/li&gt;
&lt;li&gt;usefulness of the findings,&lt;/li&gt;
&lt;li&gt;scanning flow,&lt;/li&gt;
&lt;li&gt;missing checks,&lt;/li&gt;
&lt;li&gt;and whether the tool feels useful for small teams or solo developers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project is still a work in progress, but it has already been a valuable learning experience in building security tooling that is not only technical but also understandable and useful.&lt;/p&gt;

&lt;p&gt;That, for me, is the main point of PentestScan:&lt;/p&gt;

&lt;p&gt;help developers see security issues earlier, understand them faster, and fix them with less friction.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>showdev</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
