VJOURNAL

Innovation • Global Desk • September 28, 2026

What a white-box security audit of a small website found: eight fixes on tarasovvitalii.com

VITON13 Studio reviewed the security of the founder’s portfolio site from the inside: its chat, message API, server and fifteen concept demos. It found eight issues, including script injection on the chat’s origin, fixed all eight and re-tested every fix.

Typographic cover on black: “8 found. 8 fixed.” above four findings of the tarasovvitalii.com audit, each with a severity label (high, medium, low, low) and a lime “Fixed” badge.

Answer in brief

A white-box website security audit reads the source code and configuration instead of guessing from outside. On tarasovvitalii.com it found eight issues on 28 September 2026: one high (script injection through a demo on the chat’s origin), one medium (no security policy on the demos) and six low. All eight were fixed and re-tested on a copy of the production containers.

5 sources
The audit covered a portfolio site with a sign-in chat, a small Node API that stores messages, an nginx server in Docker and fifteen concept demos.
Eight findings were confirmed by reproducing them: one high, one medium and six low; all eight were fixed and the same attacks were run again.
The serious one sat in a demo: a crafted link could run script on the origin where the chat keeps its Firebase session.

Why a portfolio site got a security review

A portfolio looks like the safest kind of website: a few pages of work and a contact form. tarasovvitalii.com, the site of VITON13’s founder, is more than that. It runs a chat on VITON ID, built on Firebase Authentication and Firestore, a small Node API that stores contact messages and sends email, an nginx server in Docker and copies of fifteen concept sites under /demos/. A visitor who signs in to write a message trusts every one of those parts at once.

On 28 September 2026 VITON13 Studio reviewed the site the way it would review a client’s site before launch. For every part the question was an attacker’s: what can someone outside do with it, and what would it cost the owner? A finding counted only once it had been reproduced, and a fix counted only once the same attack had failed against it.

Method: source code first, attacks on a local copy

A white-box website security audit starts from the inside. The reviewers read every API route and the code that verifies sign-in tokens, the Firestore rules with their 39 emulator tests, the nginx and Docker Compose configuration, the npm dependencies of the site and the API, the chat interface and the code of all fifteen demos.

Instead of probing the live server, the studio started the same containers locally, nginx and the API with production settings, and tried each attack there. That keeps a live site and its visitors out of the experiment, and it lets the same request be replayed before and after a fix to prove the change. Only the finished result, the headers and the redirects, was re-checked on the live address.

Each confirmed finding then received a severity. High meant an outsider could act inside someone else’s session or reach private data; medium meant a missing layer of defence that would turn a small bug into a large one; low meant a weakness that needs unusual conditions or leaks little. The list below follows that order, and every item records what the attack did before the fix and what the same request does after it.

The high-risk finding: script injection through a demo

The most serious problem was not in the portfolio itself but in one of its demos. The Oriva store concept read the ?cat= parameter from the address and put it into the page as HTML. A crafted link could therefore run script on tarasovvitalii.com. OWASP describes this class of bug, cross-site scripting, as injecting script into a site the victim trusts, and that is exactly what made it dangerous here.

The demos share the origin with the chat, and the chat keeps its Firebase session in the browser on that origin. One click on such a link by the site owner could have exposed the inbox and the owner account. The fix is simple once found: the demo now accepts only known category and sort values and ignores anything else. The other fourteen demos were checked for the same pattern and only compare address parameters with fixed values.

A security policy and pinned scripts for the demos

The medium-risk finding was about defence in depth. The /demos/ section sent no Content-Security-Policy, the header that tells a browser which sources a page may load scripts, styles and data from. On top of that, 52 demo pages loaded Leaflet, a map library, from a public CDN without an integrity hash. If that CDN were ever compromised, or if any script were injected, nothing would limit what it could reach.

Now /demos/ has its own policy: requests only to the site itself, scripts only from the site and the pinned library, no plugins. Leaflet is pinned with Subresource Integrity hashes, so a browser refuses the file if a single byte changes. In headless Chrome all 119 demo pages loaded under the new policy with zero violations.

Header injection in a server redirect

The nginx rule that redirected /demos/<id> to /demos/<id>/ echoed the decoded path back into the Location header. A link containing %0d%0a, the encoded line break, could therefore add a header of its own to the response, for example Set-Cookie. OWASP files this under CRLF injection: a carriage return and line feed smuggled into a place where the server builds headers.

The redirect now accepts only letters, digits, hyphens and underscores and builds the target address itself. The same request that used to return a 301 with an injected cookie now gets a plain 404, both on the local copy and on the live site.

Five smaller fixes around mail, limits and the server

Three low findings concerned the message system. An email address like me@x.com?bcc=…&body=… passed validation, so the Reply link in the owner’s inbox could open with a hidden copy recipient and pre-filled text; such addresses are now refused and every address in a mailto: link is encoded. Names could carry direction-override characters that disguise text; those are stripped. Limits were per IP address only, so rotating addresses could fill the disk; a global daily cap of 500 stored submissions now sits on top.

The rest were server settings. The message API ran as root with a writable filesystem; it now runs as an unprivileged user on a read-only filesystem with every Linux capability dropped. Every response showed the exact nginx version from a branch that no longer receives fixes; the version is hidden and the container runs the current stable line. HSTS, the header that keeps browsers on HTTPS, was sent on the main domain but not on www; it now covers www and subdomains.

Parts of the site that passed unchanged

An audit that lists only problems hides half of its value. The review also confirmed what was already done well: sign-in token verification accepts only RS256, requires a key id and checks the audience, the issuer and the expiry; the Firestore rules let no one read another person’s thread or write as the owner; the email templates escape every value; the logs contain no tokens, email addresses or IP addresses; and the chat never inserts a visitor’s text as HTML.

After the fixes the API test suite passes 48 of 48 with the new rules covered, and npm audit reports no known vulnerabilities in the dependencies of the site or the API.

On the live address the same day the response headers were checked once more: no server version in any response, HSTS with subdomains on both the bare domain and www, the demo policy on /demos/, and the header-injection request answered with a plain 404. The Oriva catalogue on the live site now compares the category with its fixed list before using it, and the map library loads with its integrity hashes.

Limits of an audit run by the site’s own studio

This is the studio’s own site, reviewed by the studio. It is not an independent penetration test and not a certificate, and it covers the code as it stood on 28 September 2026. New code, new dependencies or a new demo need the same review again, which is why a security check belongs in a release process rather than in a one-off project.

One structural risk remains by choice: the demos still share the site’s origin. The new policy limits what injected code could reach, but only moving the demos to a separate domain would isolate them completely. For a small business the lesson is practical: the most dangerous line of code is often in the forgotten extra page, not in the login form.

Practical checklist

  • List every part of the site that runs code: forms, chats, APIs, admin pages and old demos.
  • Check that each page with a login or a session sends a Content-Security-Policy.
  • Pin every script loaded from a CDN with an integrity hash or host it yourself.
  • Search the code for address parameters written into the page as HTML.
  • Make sure HSTS is sent on both the bare domain and www, and hide the server version.

Questions and answers

What is a white-box website security audit?

It is a review done with access to the source code and server configuration. Instead of guessing from outside, the reviewer reads the code, finds likely weaknesses and then reproduces them on a copy of the real setup.

Why was a concept demo the riskiest part of the site?

The demos run on the same origin as the chat, which keeps its sign-in session there. Script injected through a demo could therefore act inside the owner’s session, even though the demo itself holds no data.

Does a Content-Security-Policy replace fixing the bug?

No. The policy limits what injected code can load or reach, which reduces the damage. The injection itself still has to be fixed, as it was here by accepting only known values.

Is this audit a penetration test or a certificate?

Neither. It is the studio’s own review of its own site from the source code, with attacks reproduced on a local copy of the production containers. An independent test would be a separate engagement.

How often should a small website repeat such a review?

Whenever code, dependencies or third-party scripts change in a meaningful way, and at least before each major release. Running npm audit and a header check on every deploy covers part of it automatically.

Read next