OWASP VWAD Case Study

VWAD Product Stewardship

OWASP logo

Quick Highlights

Overview

Rito's work on the OWASP Vulnerable Web Applications Directory spans two generations of the same product. He entered through a broken mobile table, expanded the legacy directory into a more capable search product, then carried those lessons into the architecture of its rebuilt successor.

The implementation changed, but the product knowledge did not. Across the two codebases, the work moved from interaction rescue into search architecture, data normalization, static publishing, machine discoverability, installability, maintainability, and production performance.

Product Background Context

The OWASP Vulnerable Web Applications Directory is a curated catalog of intentionally vulnerable applications used for security education, testing, and research. The basic product problem sounds simple: organize a list of applications. In practice, the catalog has to support dense technical comparison, casual browsing, precise filtering, contributor inconsistency, machine discovery, and a wide range of devices.

Rito's contributions began on the legacy owasp.org implementation in late 2025. When VWAD later moved to a standalone rebuilt platform, he continued contributing to the same product line rather than treating the new codebase as an unrelated project.

The Directory Breaks Down on Mobile

Product question: How do you make a dense technical table usable on a small viewport without destroying the information density that makes the table useful?

The legacy VWAD directory was built around a wide, information-dense table. On mobile, the browser tried to compress that structure into the available viewport. Columns collapsed into near-vertical text, badges and icons shrank to illegible sizes, and the page itself overflowed horizontally. Long tables also pushed the controls far away from the user.

Rito opened issue #169 and shipped PR #171. The important constraint was explicit: preserve the content, rows, columns, headers, tabs, and ordering. The information model was not the problem. Its behavior at narrow breakpoints was.

The solution treated width as a real constraint instead of pretending the table could collapse indefinitely. Stable column widths preserved readable content, a contained scroll region handled horizontal movement without making the whole page overflow, a bounded table height kept tabs nearby, and sticky headers preserved column context while users moved through the catalog.

&
Before
After

From Browsing to Querying

Product question: How much search complexity should a technical directory expose without turning every interaction into a query builder?

Once the table was navigable, the next limitation was discovery itself. A usable catalog still forces users to scan when the interface cannot express the combinations they care about. Rito's Advanced Search PR #210 turned the table into a multi-parameter query interface spanning keywords, technologies, references, GitHub stars, and year ranges.

The interaction model separated deliberate query composition from lightweight edits. Changes inside the Advanced Search modal remained draft state until Accept was pressed, so building a complex query did not continuously mutate the table underneath the user. Outside the modal, removing pills, changing the keyword, or clearing the query updated results immediately. Multi-select fields defaulted to OR but could switch to AND when users needed exact intersections.

That feature work exposed a second-order product problem: filtering is only as coherent as the source data. Follow-up work in PR #214 and PR #217 reduced duplicate and inconsistent technology labels so contributor variation did not leak directly into the search experience.

Advanced Search Modal - Empty
Advanced search modal empty state for the VWAD directory

The legacy directory gained a dedicated query builder for composing multi-parameter searches.

Advanced Search Modal - Filled
Advanced search modal filled state with parameters and pills

Changes inside the modal remain draft state until accepted, allowing a complex query to be composed without repeatedly mutating the table.

Advanced Search Applied
Advanced search applied with filter pills and result count

Accepted parameters become removable pills in the filter bar, keeping the active query visible while preserving direct actions such as keyword search and clear.

A Rebuild Without Starting Over

Product question: When a product is rebuilt from scratch, which lessons should survive even when the old implementation does not?

A few months later, VWAD moved to a standalone rebuilt implementation. The new codebase removed many legacy constraints, but the discovery problem remained. Rito's PR #30 preserved the rebuilt site's simpler search as a dedicated Basic mode while adding an Advanced mode for grouped multi-select filters, AND/OR matching, stars, year ranges, mode-specific state, and removable grouped pills.

The review surfaced a useful boundary between beginner clarity and expert capability. Maintainer kingthorin questioned whether filtering by references made sense when those references were not displayed in the browse interface. Rito agreed that the label should be clearer and changed it to "Reference type(s)," but argued that some additional complexity was acceptable inside an explicitly Advanced mode, especially because the capability remained useful to experienced users of the legacy site.

The compromise kept the power feature, improved its language, and contained the complexity rather than pushing it into the default experience. After the revisions, kingthorin wrote that the result "looks and works wonderfully."

Turning a Directory Into a Publishing System

Architecture question: If VWAD is a directory, should every item in the directory exist as an independently addressable web document?

The rebuilt site could display individual app details, but those details lived behind client-side hash routes. A human with JavaScript could navigate to an entry, while a crawler fetching a URL did not receive a dedicated document representing that app. For a curated directory, that limited how far the catalog could travel through search engines, crawlers, and machine-assisted retrieval.

Rito's PR #37 changed the site's publishing model. A new build step generated dedicated canonical pages at /app/<slug>/, per-app and collection-level JSON-LD, sitemap coverage, generated CSS bundles, and a deployable _site/ artifact. GitHub Pages moved from serving the branch root directly to deploying generated output through GitHub Actions.

The URL decision also required judgment about compatibility debt. Because the rebuilt site was less than a month old, the original hash URLs were treated as transitional rather than a permanent architecture contract. The cleaner static URL model became canonical, while a compatibility page continued handling the older links instead of breaking them outright.

Each vulnerable application therefore became a directly addressable, crawlable document with its own metadata and structured representation. VWAD stopped behaving only like a JavaScript application that happened to contain a directory and gained a real publishing substrate for the corpus itself.

Keeping the Architecture Proportionate

Engineering question: How much infrastructure does a lightweight open-source site actually need before simplicity turns into homegrown tooling debt?

The publishing change introduced a real build pipeline, but Rito kept it intentionally small. The generator remained Python standard-library only and added no new dependencies. Generation was paired with repo-specific validation that checked canonical URLs, page counts, sitemap coverage, structured-data shapes, compatibility behavior, and generated artifacts.

That constraint was not treated as ideology. During review, Rito found that stripping whitespace as part of a lightweight CSS minification pass caused incorrect CSS math behavior. Rather than maintain a growing set of fragile exceptions, he removed that optimization and documented the boundary: if VWAD needed deeper CSS minification, it should use a real dependency designed for that job.

The result was a deliberately narrow build system: own the simple generation logic that is specific to the product, validate what it emits, and avoid recreating sophisticated general-purpose tooling badly just to preserve a zero-dependency label.

Hardening the Rebuilt Product for Production

Product question: As the platform gains capability, what has to change underneath it so the interface still feels coherent, maintainable, and fast?

The rebuilt VWAD work continued beyond search and publishing. PR #31 split a monolithic stylesheet into smaller shared and page-specific layers, removed dead code, resolved cascade conflicts, and normalized common chrome so continued feature work had a cleaner foundation.

PR #36 added baseline installability through manifest metadata, icons, a minimal service worker, iOS standalone support, and shortcuts that could launch users directly into Basic or Advanced Search.

Finally, PR #41 reduced layout instability by pre-rendering the featured-app shell with loading placeholders before data arrived, then fading in loaded content while respecting reduced-motion preferences. The maintainer, kingthorin, reported that the change made a "huge difference" to PageSpeed and later added before-and-after screenshots to the review thread.

Conclusion

The strongest signal in the VWAD work is continuity. Rito did not make one isolated improvement and leave. He rescued a failing interaction in the legacy product, expanded its search model, followed the product into a new codebase, and continued shaping how the rebuilt system is browsed, published, discovered, installed, validated, maintained, and loaded. Two implementations were involved, but the ownership stayed centered on one evolving product problem.