Skip to content

Feature-based threat modelling

A student portal adds a new upload feature. Students can submit homework, and teachers can leave feedback.

That sounds small enough to build. A form, a file input, a submit button, a page for the teacher.

It is also small enough to threat model properly.

Feature-based threat modelling takes one feature and walks it from start to finish. At each step, you ask what could go wrong and what the code needs to check.

Walk the feature

Start with the normal story:

  1. A student signs in.
  2. The student uploads a file.
  3. The server stores it.
  4. A teacher opens the submission.
  5. The teacher leaves feedback.
  6. The student reads the feedback.

That list is the map. You do not need a fancy diagram to start.

Now mark the places where a value crosses a trust boundary:

StepValue crossing the boundaryWhat to ask
UploadFilename, file type, file sizeDid the server check the file itself?
StorePath and metadataCan one student overwrite another file?
Teacher viewSubmission idIs this teacher assigned to this student?
FeedbackFeedback textCan it become script when displayed?
Student viewFeedback idCan one student read another student's feedback?

The feature now has shape. You can see where security decisions belong.

Start with the story, then add the threats

If you start with threat names, the exercise feels abstract.

If you start with the feature story, each threat has somewhere to land.

JunoWalk the feature Start with the normal story. Who signs in, what they send, where it goes, who reads it later?

Then mark the moments where your app receives something it did not choose. Those are the spots where the server needs to ask more questions.

JunoWalk the feature The practical move is to turn the feature into rows. Step, value, boundary, check. That format keeps the model close to code.

For the upload feature, the hot spots are the file itself, the stored path, the submission id, the teacher feedback and the student view. Each one maps to a handler or storage decision you can test.

JunoWalk the feature Feature models work because they are small enough to finish. The tradeoff is that they inherit whatever structural problems the system already has.

If every feature depends on the same weak role model, you'll keep finding the same threat in different clothes.

That's the point where the feature model has done its job and is telling you to schedule a wider system sweep. Annoying, yes. Cheaper than pretending the fifth duplicate finding is new information.

Turn threats into checks

A feature model should not end as a list of worries.

For the upload feature, a worry might be:

A student could upload something unsafe.

That is true, but it is too vague to build from. Make it a check:

  • Limit file size before storage.
  • Allow only expected file types.
  • Generate the stored filename on the server.
  • Store files outside the public app directory.
  • Check the teacher is assigned to the student before showing the file.

Now the model can become acceptance criteria.

A threat becomes useful when the next developer can turn it into code or a test.

JunoTurn threats into checks A worry says what scares you. A check says what the app's going to do about it.

"Unsafe upload" is a worry. "Limit file size and generate the stored filename on the server" is a check someone can build.

JunoTurn threats into checks Write checks in the same language as the ticket. That keeps the model alive after the meeting.

For example: teacher can view a submission only when the server confirms the teacher is assigned to that student. That sentence becomes a route check and a test case without translation.

JunoTurn threats into checks The check has to live where the decision is made. A disabled button in the teacher UI is helpful, and it isn't the control. The route serving the file is the control.

This is where old systems get expensive. One feature may have three paths to the same data: the web route, the admin tool and the background export. If the check sits in only one path, the model found a door and the implementation built a curtain.

Try it on teacher feedback

Now use the same method yourself.

The feature says: teachers can leave feedback on student submissions.

Answer the five feature-based questions before reading on.

  1. Who sends the value?
  2. Who reads it later?
  3. What decision matters?
  4. What could go wrong?
  5. What should the code check?
Compare your answers
QuestionA reasonable answer
Who sends the value?The teacher sends feedback text.
Who reads it later?The student, and possibly another teacher.
What decision matters?Only an assigned teacher can leave feedback.
What could go wrong?Feedback could contain script, or land on the wrong submission.
What should the code check?Assignment on the server, text length, and safe output when displayed.

Question 2 is the one that carries the most weight and gets the least attention. Naming who reads a value later is what tells you it will be rendered into a page, which is what makes "could contain script" a question worth asking at all.

Answer only question 1 and you get input validation. Answer question 2 as well and you get output safety too.

The exact fix comes later in the handbook. The habit matters now: walk the feature, mark the boundary, write the check. That's the whole method.

The front end can guide, but the server decides

The page can hide feedback controls from teachers who are not assigned.

The route still has to check the assignment, because anyone can call the route directly.

JunoTry it on teacher feedback Teacher feedback looks like text in a box, but the feature has several decisions inside it.

Who may write it? Which submission does it belong to? Who may read it later? Security thinking is noticing those decisions before the code quietly answers them for you.

JunoTry it on teacher feedback Feedback has two common bug shapes: the wrong person can write it, or the right text becomes unsafe when shown later.

That gives you two checks in different places. Authorization belongs in the route that saves feedback. Safe output belongs where the feedback is rendered. Same value, different destination, different rule.

JunoTry it on teacher feedback Stored text is patient. It can sit harmlessly in the database for months, then become dangerous when a new page renders it into a different context.

That's why feature models should name destinations, not only inputs. "Feedback text is displayed to students and teachers" is more useful than "feedback text is stored". The second sentence tells you where the data sleeps. The first tells you where it can wake up and ruin your afternoon.

Where this goes next

Feature-based threat modelling is the day-to-day version of STRIDE. You can run it inside planning, write the checks into the ticket, and test them before the feature ships.

Next, OWASP and live bugs changes the timeline. Instead of asking what could go wrong before release, it gives names to the things that already went wrong in real apps.