Skip to main content
Blog

Process

A secure development process for small teams

Lightweight threat modelling, a code review checklist, secrets hygiene, CI checks, a release checklist and a pre-audit before the expertise. A practical routine for a team of 3-10.

· 11 min read

Photo: helloquence, CC0 · Wikimedia Commons

In large companies, a secure development process is built with a dedicated team, long documents and expensive tools. A team of three to ten people has neither the time nor the headcount for that. As a result, security lands on the "we'll look at it after release" list and comes back in the official expertise report as a dozen findings at once.

In this article we propose a minimal process a small team can actually follow: a fifteen-minute threat review during planning, a short code review list, secrets hygiene, automated CI checks and a pre-release check. Each step fits into your existing workflow and does not require a separate "security phase".

What the problem is

The typical situation in small teams:

  • security decisions are not written down anywhere and live in one person's head;
  • code review only answers "does it work?";
  • .env files, keys and test passwords end up in the repository from time to time;
  • dependencies (composer, npm, pub) go un-updated for years;
  • releases go out in "we need this now" mode, without a checklist;
  • the first security check happens only at the official expertise.

In the expertise of our own product (a tax and finance SaaS platform), the web part had 6 findings and the mobile app had 9. Most of them were not sophisticated attacks but things forgotten in the process: a payment success page shown before the payment was confirmed, trusting the X-Forwarded-Host header, the full route list exposed to the browser, open panel ports, and no root detection or certificate pinning in the mobile app. We closed them all, but each could have been caught much earlier with a simple checklist.

Why it matters for the expertise

The official expertise examines a finished product. Every finding means rework, resubmission and waiting. Building security into the process reduces the number of findings and lets you close the rest quickly, because the team knows where everything is. Documents such as OWASP SAMM and OWASP ASVS recommend this approach; a small team can take the parts it needs.

Principle: security is not a separate phase, but a few questions at every phase.

1. Lightweight threat modelling

For every new feature (especially payments, authentication, file upload, external integrations), set aside 15 minutes during planning and write down answers to four questions:

  1. What are we building? Where data comes in, where it is stored, who can see it. A simple diagram is enough.
  2. What can go wrong? Use STRIDE as a prompt list: pretending to be someone else (Spoofing), modifying data (Tampering), denying an action (Repudiation), information disclosure, denial of service, elevation of privilege.
  3. What are we going to do about it? A concrete measure for each risk: a check, a restriction, a log entry.
  4. Did we do a good job? Measures are confirmed by a test or a review.

Example: for a "payment" feature, the question "can the user see the success page before the payment provider confirms?" — that was one of our findings. More: success page before payment confirmation.

Keep the answers as short text in the issue or in a docs/threats/ folder.

2. Code review checklist

Add a short list to your pull request template. For GitHub, .github/pull_request_template.md:

### Security
- [ ] New endpoints check authentication and object-level authorisation
- [ ] User input is validated, SQL is parameterised only
- [ ] Output to HTML is escaped (Blade {{ }}, no dangerouslySetInnerHTML in React)
- [ ] File uploads restrict type, size and storage location
- [ ] No secrets, keys or passwords in the code
- [ ] No passwords, tokens or personal data in logs
- [ ] If a dependency is added: is it needed, is it maintained

The reviewer goes through each item. The areas that need the most attention are authorisation (a user cannot open another user's object), business logic states and outbound requests. A Laravel example:

// Bad: by ID only
$invoice = Invoice::findOrFail($id);

// Good: ownership is checked
$invoice = $request->user()->invoices()->findOrFail($id);
// or via a Policy
$this->authorize('view', $invoice);

More: IDOR and authorisation errors.

3. Secrets hygiene

  • .env, key files and configs such as google-services.json go in .gitignore;
  • the repository contains only .env.example without values;
  • separate keys for each environment, and no production keys on developers' machines;
  • if a key leaks — rotate it first, then clean the history.

Add a secret scanner such as gitleaks to a pre-commit hook and to CI:

gitleaks detect --source . --redact

Check the history too: a key that was committed once stays in git history even if the next commit removes it. More: managing secrets and keys.

4. CI checks

Automated checks run on every pull request and catch what people forget. A GitHub Actions example:

name: security
on: [pull_request]
jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - name: Secrets
        uses: gitleaks/gitleaks-action@v2
      - name: PHP dependencies
        run: composer install --no-interaction && composer audit
      - name: JS dependencies
        run: npm ci && npm audit --audit-level=high
      - name: Static analysis
        run: pipx run semgrep --config p/owasp-top-ten --error

At first, fail the build only on high-severity findings, otherwise the team will quickly switch the check off. Lower the threshold over time. For Flutter projects, flutter analyze and dart pub outdated add value; for Laravel, Larastan (PHPStan). Enable Dependabot or Renovate to keep dependencies up to date.

5. Release checklist

Before every production release (or at least before every major one), go through a short list:

  • APP_DEBUG=false, APP_ENV=production, no stack traces on error pages;
  • security headers (HSTS, CSP, X-Content-Type-Options) are present in responses;
  • the list of new routes and API endpoints has been reviewed, test and debug routes are disabled;
  • migrations run after a backup has been taken;
  • for the mobile app: a release build, obfuscation enabled, debuggable off, allowBackup=false, cleartext traffic disabled, APK/IPA checksums recorded;
  • the rollback path is known.

You can check quickly with these commands:

curl -sI https://example.uz | grep -iE "strict-transport|content-security|x-content-type|server:"
php artisan route:list --except-vendor | grep -iE "test|debug|telescope"

Related articles: security headers, debug mode and information disclosure, APK/IPA checksums.

6. Roles and responsibility

Even if a small team has no dedicated security specialist, name one "security owner". Their job is not to do everything themselves, but to:

  • make sure CI checks keep running and warnings get reviewed;
  • check dependency and server updates once a month;
  • follow new vulnerability announcements (for the frameworks and libraries in use);
  • be the first point of contact during an incident.

7. A pre-audit before the expertise

The process above reduces everyday mistakes but does not replace an outside view. A team gets used to its own code and misses some things. An independent check before the official expertise gives you:

  • a list of findings in the categories the expertise checks, with severity levels;
  • a concrete fix and a re-test for each finding;
  • readiness of the documents and files to be submitted for the expertise.

More: why a pre-audit is needed and checklist before the expertise.

Where to start

Do not try to roll everything out in a week. A practical order:

  1. First week: set up .gitignore and gitleaks, scan the repository history for secrets and rotate any keys you find.
  2. Second week: add security items to the PR template and enable composer audit / npm audit in CI.
  3. First month: write the release checklist and use it on the next release; enable Dependabot or Renovate.
  4. Following months: add static analysis, make threat review for important features a habit, and revisit the process once a quarter.

After each step, have a short discussion with the team: what became extra overhead and what actually helped. A process that does not fit the team is quickly forgotten.

Short checklist

  • A 15-minute threat review for important features, with written answers
  • Security items in the PR template, checked during review
  • No .env or keys in git, gitleaks in pre-commit and CI
  • composer audit, npm audit and static analysis run in CI
  • Dependabot or Renovate enabled
  • A release checklist (debug, headers, routes, mobile build settings)
  • A named security owner
  • An independent pre-audit planned before the official expertise

Summary

Secure development for a small team is not thick documents but a few habits repeated at every stage. When they work together, a product arriving at the expertise has noticeably fewer unexpected findings. In our process, the Claude AI agent quickly reviews the codebase, configuration and CI settings, and the expert confirms the findings, fixes them and helps your team set up the process.

If you want to know how ready your product and process are for the expertise, request a security scan. We will help you close the gaps before the official check.