Security work / Public application / Engineering case study

Pet Sticker Maker, under the microscope.

I made a tool that turns pet photos into transparent stickers for Catflakes. Making it work was one problem. Looking at it as a security engineer raises another: what happens when an API takes untrusted photos and asks a server to process them?

React + ViteFastAPI + PythonImage processingGitHub ActionsSecurity review: ongoingSource repo: private
01 / Why this matters

A useful little app with a real attack surface.

The app has a browser frontend and a Python backend that accepts uploads, reads image content, runs segmentation, and returns a cutout or finished PNG. It can also hand assets off to Catflakes. The inputs look harmless—pictures of cats—but they are still files supplied by people I don't control.

I wanted to look beyond “does it produce a sticker?” and ask which assumptions live at the boundary: what the file actually contains, what processing might cost, what the API exposes, and what GitHub checks before changes ship.

01 / BrowserReact/Vite: image selection, crop, preview, editing controls
02 / APIFastAPI: multipart upload, image validation, segmentation and rendering
03 / OutputPNG/base64 result or temporary Catflakes package handoff

Scope: this is a source-based security case study of an application I built, not a penetration test or a claim that every proposed control is deployed. The application can be used publicly; its GitHub source links are private.

02 / What exists today

What I already had in place.

Checking the upload

The API checks that the declared content type starts with image/ and uses Pillow to verify that the bytes can be opened as an image. Invalid image data gets an HTTP 400 response.

Normalizing options

FastAPI parses typed form fields. Rendering options pass through a normalization step before they reach the image pipeline.

Reusable processing

A combined processing endpoint segments a photo once; rendering from an existing cutout avoids repeating the heavier step for every border or crop adjustment.

Tests + deploy workflow

GitHub Actions runs Python tests and a frontend build on pushes and pull requests. A separate Pages workflow sets explicit read, Pages-write, and OIDC-token permissions.

Tests cover successful image processing, PNG dimensions, candidate detection, Catflakes asset round-trips, and segmentation behavior. These are useful regression checks, but successful feature tests do not establish that hostile inputs are handled safely.

Backend tests (Private) →

03 / What I would harden

Where the current implementation needs work.

Bound the work an upload can trigger

Today, _read_image_upload() reads the full file into memory before verifying it. I don't see explicit maximum request bytes or decoded-image pixel limits in this path. A valid but oversized or unusually complex image can still put pressure on CPU and memory. My next change would be bounded reads, decoded-dimension limits, and tests for the rejection behavior.

Make browser origins deliberate

The API currently configures CORS with allow_origins=["*"] and allow_credentials=True. I would specify the frontend origins and determine whether credentials are needed at all. CORS is a browser policy, not API authentication, so it shouldn't be treated as the only access control.

Put limits on temporary assets

The Catflakes bridge stores submitted packages in an in-process dictionary keyed by generated IDs. It's a convenient prototype, but there is no enforced expiry, per-object size ceiling, or authentication in that code path. I would add TTL cleanup, limits, and a clear rule for what the asset ID authorizes.

Turn CI into a security check, too

Current CI runs tests and a build. It does not currently show CodeQL, dependency scanning, secret scanning, DAST, or security-based merge blocking. I'd add SAST and dependency review incrementally, fix actionable findings, and only then describe them as operational controls.

Not a vulnerability confirmation

These are observations from the current source and proposed hardening priorities. I have not claimed exploitation, measured impact, or completed remediation where the repository does not show it.

04 / Practical next pass

What I'd implement and how I'd know it works.

  1. Upload boundaries: enforce maximum bytes and decoded dimensions; add malformed, wrong-type, truncated, and oversized-image tests.
  2. API and sharing: restrict CORS as appropriate; bound temporary asset size and lifetime; test missing, expired, and oversized assets.
  3. Pipeline: add CodeQL for applicable languages, dependency updates/review, and secret detection; document which checks actually fail a pull request.
  4. Evidence: link the real workflow, tests, security finding, code fix and verification run here. No green checkmark without evidence.

This is the direction I want for my software projects in general: security controls that are part of how the app is built and tested, not a security paragraph added after release.

05 / What it demonstrates

What I would fix before calling this secure.

The engineering work here is real: a browser app, an image-processing API, integration with another project, automated tests, and deployment workflows. The security work is a transparent review in progress. I'd rather show the actual boundary decisions and the work left to do than claim a “secure CI/CD pipeline” that I haven't built yet.

Related: what I learned doing vulnerability research in NYU AppSec →