From 36 Vulnerabilities to Zero: Securing an Internal Web App

Table of Content
    Share to

    Facing similar infrastructure challenges?

    Let's talk through what a hardened, audit-ready environment looks like for your stack.

    Book an assessment

    01 Background

    The client

    Dapper Detailing Pros is an auto detailing company in Canada. They clean, restore and protect vehicles, at enough volume that the business runs on software rather than on paper.

    That software is their internal web application: the operations portal staff use to run the day, covering jobs, scheduling, people and the customer records attached to all of it. No customer ever sees it. It is simply the thing the business stops without.

    Sector
    Auto detailing
    System
    Internal operations app
    Users
    Staff only
    Engagement
    15 days

    02 Diagnosis

    The problem

    There was no incident. Nothing had gone wrong. That is exactly the position this work should happen from, and exactly why it usually doesn’t.

    Open vulnerabilities 5 · 11 · 20 Five critical, eleven high and twenty medium issues, thirty-six in total, in software holding customer records and running daily operations.

    Those grades are a standard scale, not our opinion. Critical means act now. High means real damage if someone found it. Medium means a genuine weakness that is harder to reach.

    The count is not the useful part. Two gaps let 36 issues accumulate without anybody being careless:

    1. Nobody had ever read the code adversarially

      The developers were solving business problems, and solving them well enough that the company runs on the result. Reading your own code as an attacker would is a different activity from writing it, and it does not happen by accident.

    2. Nothing checked the code on its way out

      No automated security testing sat between writing a change and running it in production. Every one of the 36 issues walked through that gap unchallenged.

    What we ruled out

    Running a scanner over the application would have found a good number of these, and it would not have been enough. A tool cannot tell you that a member of staff on one account can open a record belonging to a different customer, because nothing about that code looks dangerous. It looks like working code doing what it was written to do.

    03 Execution

    Our solution

    We used automation for coverage and human review for judgement, then changed how code ships so the reviewed version is the version that runs.

    1. Ran SAST across the whole application first

      SAST is static application security testing: a tool that reads source code and flags known-dangerous patterns without running it, such as unsafe handling of user input, weak encryption and credentials left in code. It comes first because it clears the mechanical findings cheaply, so expensive human attention goes only where human attention is required.

    2. Then read the code properly, as an attacker would

      The manual review targeted what a scanner structurally cannot reach: access control, meaning whether a legitimately logged-in user can reach data belonging to someone else; business logic, where valid steps combine into an outcome nobody intended; trust assumptions, where the code believes something it was told rather than something it verified; and sensitive data handling, including what ends up in logs and error messages.

      Every one is invisible to a scanner, because in each case the flaw is in what the code was written to do.

    3. Fixed in severity order, worst first

      The 5 critical, then the 11 high, then the 20 medium. Each fix was reviewed on the way out rather than assumed correct, because a rushed security fix is a reliable way to introduce the next issue.

    4. Changed how code reaches production

      None of it holds past the next release unless the shipped code is the reviewed code. Deployment was tightened into a single defined path: changes go out one way, through the same steps, with security testing running as part of that path rather than as something a person remembers. What runs in production traces back to what was reviewed.

    5. Made the checks a condition of shipping

      Findings in a report get read when someone has time. Findings that block a release get fixed. Serious issues now stop the release, so nobody has to be the person who says no. The process says no.

      The portal stayed live throughout and staff kept working in it every day.

    04 Duration

    Timeline

    Start to handover 15 days from first review to all 36 issues closed and the new release process in place.

    05 Stack

    Tech stack

    • Internal operations web app
    • SAST
    • Manual secure code review
    • Dependency scanning
    • Single defined deployment path
    • Release-blocking security checks

    06 Outcome

    The outcome

    Issues closed36 → 0Every severity, worst first
    Delivered in15 daysFirst review to handover
    Critical remainingZeroAnd new ones block the release
    DowntimeNoneStaff kept working throughout
    Delivered
    Criteria
    // After BPDoxS
    // Before As we found it
    Critical issues
    0 remaining
    5 open
    High issues
    0 remaining
    11 open
    Medium issues
    0 remaining
    20 open
    Automated testing
    Runs on every change
    None anywhere in the process
    Human code review
    Complete, across the application
    Never performed
    Access control flaws
    Reviewed by a person, not a tool
    Unexamined, and invisible to any scanner
    Path to production
    One defined path, same steps every time
    Undefined, with steps done by hand
    New serious findings
    Block the release
    Would reach production unchallenged

    Thirty-six issues closed in fifteen days, and a release process where the code that ships is the code that was reviewed.

    // RELATED WORK

    Related case studies

    See all case studies
    Loading related case studies...