Skip to main content

Application Security Guidelines

These guidelines define the mandatory application security baseline for every developer and DevOps engineer at Sadeem Informatique. They are written in the same spirit as the security controls enforced by SATIM for payment integrations: explicit, verifiable, and non-negotiable on production systems.

Security is not a phase at the end of a project — it is a deliverable of every feature, every sprint, and every release.

Non-negotiable

Any item marked Mandatory in this document blocks a production release if not satisfied. If you believe an exception is justified, it must be approved in writing by the System Information Chief before deployment — not after.

1. Communicate Before You Build

Security review happens before implementation, not during the post-mortem.

Mandatory:

  • Any new feature that touches authentication, authorization, payments, personal data, file uploads, external integrations, or admin/backoffice privileges must be flagged to the security/architecture lead before development starts.
  • If a feature changes how tokens, sessions, roles, or permissions work, open a short design note (ticket, PR description, or architecture doc) describing the security impact before writing code.
  • When in doubt about whether something is "security-sensitive," ask. Silence is treated as non-disclosure, not approval.
Cheap early, expensive late

A five-minute conversation before implementation is far cheaper than a rewrite after a penetration test finds the flaw in production.

2. Authentication & Password Management

OTP on Password Reset (Mandatory)

  • Every "forgot password" / "reset password" flow must require OTP (One-Time Password) verification, in both the frontend and the backend.
  • Frontend enforcement of the OTP step is a UX convenience only — it is never a security control by itself. The backend must independently verify the OTP before allowing a password change, regardless of what the client sends.
  • OTPs must:
    • Be single-use and invalidated immediately after successful verification or password change.
    • Expire within a short, defined window (e.g., 5–10 minutes).
    • Be rate-limited (attempts and resend requests) to prevent brute-force and spam.
    • Never be logged in plaintext (application logs, error trackers, analytics).
Never trust the client

A reset-password endpoint that changes a password without re-validating the OTP server-side is a critical vulnerability, even if the frontend "requires" it. Treat every backend endpoint as if the frontend does not exist.

Current Password on Change-Password (Mandatory)

  • Every "change password" flow (a logged-in user changing their own password) must require the user to re-enter their current password, verified server-side, before the new password is accepted.
  • This applies even when the user is already authenticated with a valid session/token — an active session is not proof the current person at the keyboard is the account owner (shared devices, hijacked sessions, unattended laptops).
  • On successful change, invalidate all other active sessions/tokens for that account (see Token Blacklisting) and notify the user by email of the change.

General Authentication Rules

  • Passwords are always hashed with a strong, modern algorithm (bcrypt/argon2). Never store or log plaintext passwords.
  • Enforce a minimum password policy (length, complexity) consistently on frontend and backend.
  • Lock or throttle accounts after repeated failed login attempts.
  • Multi-factor flows (OTP, email confirmation links) must always be validated server-side, never trusted from client state.

3. Token Management (Web vs. Backoffice)

Separation of Tokens (Mandatory)

  • Web (customer-facing) and Backoffice/Admin applications must use separate token issuance, separate signing secrets/keys, and separate token scopes.
  • A token issued for the web app must never be valid for backoffice endpoints, and vice versa. Validate the token's intended audience/scope on every protected endpoint.
  • Backoffice tokens must carry stricter constraints: shorter lifetimes, tighter IP/role checks where feasible, and no reuse across environments.

Token Blacklisting (Mandatory)

  • Implement a token blacklist/revocation mechanism (e.g., server-side denylist, Redis-backed revoked-token store, or short-lived tokens with refresh rotation) so that:
    • Logout actually invalidates the token — it cannot still be used after logout.
    • Password changes, role changes, or account disablement invalidate all previously issued tokens for that user.
    • Compromised tokens can be revoked on demand without waiting for natural expiry.
  • Web and backoffice blacklists must be maintained independently, consistent with their separate token spaces.
Stateless is not "unrevokable"

If you choose JWTs for statelessness, you still need a revocation strategy. "The token will expire eventually" is not an acceptable answer for logout or account compromise.

4. Input Validation (Frontend & Backend)

Mandatory:

  • All user input is validated on both the frontend and the backend. Frontend validation is for user experience; backend validation is the actual security boundary.
  • Backend validation must never be skipped because "the frontend already checks it" — the frontend can always be bypassed (direct API calls, modified requests, scripts).
  • Apply validation to:
    • Data type, format, length, and allowed value ranges.
    • Query parameters, path parameters, and headers, not just form/body fields.
  • Use parameterized queries / ORM query builders exclusively. Never build SQL, NoSQL, or shell commands via string concatenation with user input.
  • Sanitize and encode output to prevent XSS; escape data appropriately for the context it's rendered in (HTML, JS, URL, attribute).
  • Reject unexpected fields on the backend rather than silently accepting them (avoid mass-assignment vulnerabilities).

Uploaded Media & File Validation (Mandatory)

  • Validate uploaded files by an allowlist of accepted types — never a blocklist.
  • Verify the real file type server-side by inspecting content (magic bytes/MIME sniffing), not just the filename extension or the client-supplied Content-Type header.
  • Enforce maximum file size and, for images, maximum dimensions before accepting an upload.
  • Re-encode/re-process images server-side (resize, transcode) rather than storing the raw uploaded bytes as-is — this strips embedded payloads and most metadata (EXIF/GPS).
  • Never accept .svg, .html, or other markup/script-capable formats in a media upload field unless explicitly required and rendered in a sandboxed, script-disabled context.
  • Serve user-uploaded media from a storage domain/subdomain separate from the main application (or with Content-Disposition: attachment / a locked-down CSP) so a malicious upload cannot execute in the context of the main app (stored XSS via uploads).
  • Scan uploads for malware where the risk profile justifies it (public uploads, étatique/government projects, documents shared internally).

5. Rate Limiting on Authentication Endpoints (Mandatory)

Every authentication-related endpoint must be rate-limited, per IP and per account, at minimum:

  • Login
  • Registration / sign-up
  • OTP request (send) and OTP verify
  • Reset-password request and reset-password confirm
  • Change-password
  • Email/phone verification and any endpoint that triggers an outbound email or SMS

Apply CAPTCHA on top of rate limiting where the endpoint is public and abuse-prone (login, registration, OTP request). Return generic error messages on these endpoints (do not reveal whether an email/username exists in the system).

Unthrottled auth endpoints are an open door

An auth endpoint without rate limiting is a brute-force and OTP-guessing vector, and an easy way to exhaust SMS/email quotas. This is checked on every release, not just at initial launch.

6. API & Environment Hardening

Disable API Documentation in Production (Mandatory)

  • Swagger/OpenAPI UI, GraphQL Playground/Introspection, Postman-published docs, and any other interactive API documentation must be disabled in production environments.
  • These tools may remain enabled in local, dev, and staging environments only, and must sit behind authentication if staging is internet-reachable.
  • This applies regardless of framework: springdoc/swagger-ui, NestJS @nestjs/swagger, DRF drf-spectacular, Laravel l5-swagger, etc. — disable or gate the route by environment variable/config before shipping.
Do not expose your API surface

Public Swagger/GraphQL docs on production hand attackers a complete map of your endpoints, parameters, and data models. Verify this is disabled as part of every release checklist, not just once at project setup.

Private Storage for Sensitive Data (Mandatory)

  • Object storage buckets (S3, MinIO, or equivalent) holding sensitive data — user documents, invoices, ID scans, backups, private uploads — must be private, never public-read.
  • Serve access to private objects through short-lived, signed/presigned URLs generated server-side, not permanent public links.
  • Public buckets are only acceptable for genuinely public static assets (site logos, public marketing images), and that choice must be a deliberate, reviewed decision, not a default.
  • See the VPS & Server Security Guidelines module for the infrastructure-level configuration.

General Hardening

  • Disable framework debug modes, stack traces, and verbose error responses in production (APP_DEBUG=false, NODE_ENV=production, etc.).
  • Remove or protect default/admin endpoints, health-check endpoints with sensitive detail, and any /actuator, /debug, /test routes before go-live.
  • Enforce HTTPS/TLS everywhere; redirect HTTP to HTTPS; set secure cookie flags (HttpOnly, Secure, SameSite).
  • Apply the principle of least privilege to database users, service accounts, and API keys — no service uses admin/root credentials for routine operations.

7. Self-Hosted / Offline Packages for État (Government) Projects

Mandatory for all "étatique" (government/public-sector) projects:

  • Third-party packages, libraries, and dependencies must be self-hosted or vendored offline — do not resolve dependencies directly from public registries (npm, PyPI, Packagist, Maven Central, etc.) at build or deploy time.
  • Set up and use an internal/private package mirror or artifact repository (e.g., Verdaccio, Nexus, Artifactory, local vendor directories) for these projects.
  • Before vendoring a package, verify its integrity (checksum/hash) and scan it for known vulnerabilities.
  • Document, in the project's README or deployment guide, exactly which offline mirror/registry is used and how it is updated.
Why this matters

État/government engagements often run in restricted or air-gapped network environments and carry stricter supply-chain requirements. Relying on live public registries risks both availability failures and supply-chain compromise (typosquatting, dependency confusion, compromised upstream packages).

8. Logging, Monitoring & Data Protection

  • Never log secrets, tokens, passwords, OTPs, card data, or full personal identifiers. Mask or redact sensitive fields in logs.
  • Centralize security-relevant logs (auth failures, token revocations, admin actions) so anomalies can be investigated.
  • Encrypt sensitive data at rest where required (PII, payment-related data) and always in transit (TLS).
  • Follow data minimization: only collect and retain the data the feature actually needs.

9. Dependency & Vulnerability Management

  • Enable and act on Dependabot (or equivalent) alerts, per Engineering Git & CI/CD Policy.
  • Track relevant OWASP Top 10 risks for your stack and apply mitigations proactively, per General Engineering Guidelines.
  • Review new dependencies before adding them: maintenance status, known CVEs, and license compatibility.

10. Developer & DevOps Delivery Checklist

Use this checklist as part of every feature's Definition of Done and every release's go-live checklist. All items are Mandatory unless marked optional.

Developer Checklist

  • Security-impacting change was flagged and discussed with the security/architecture lead before implementation.
  • Reset-password flow requires OTP verification on both frontend and backend.
  • Change-password flow requires the current password to be re-entered and verified server-side.
  • OTP is single-use, time-limited, and rate-limited.
  • Web and backoffice tokens are issued, scoped, and validated separately.
  • Logout, password changes, and account/role changes revoke (blacklist) previously issued tokens.
  • All inputs are validated on frontend and backend (type, length, format, allowed values).
  • Uploaded media is validated by real content (magic bytes), not just extension/MIME header, with size/type allowlists enforced and images re-encoded server-side.
  • All queries use parameterized statements / ORM — no raw string concatenation with user input.
  • Output is properly encoded/escaped to prevent XSS.
  • Rate limiting is implemented on login, registration, OTP, reset-password, and change-password endpoints.
  • Sensitive data written to object storage (S3/MinIO) uses a private bucket, accessed via signed URLs.
  • No secrets, tokens, passwords, or OTPs are logged or committed to the repository.
  • New/updated endpoints reject unexpected fields (no mass-assignment exposure).
  • Unit/integration tests cover the security-relevant paths (auth failure, invalid OTP, expired token, rejected input, rate-limit trigger).

DevOps / Release Checklist

  • Swagger/OpenAPI, GraphQL Playground/introspection, and any interactive API docs are disabled in the production environment.
  • Debug mode, verbose errors, and stack traces are disabled in production.
  • HTTPS/TLS is enforced on the application and on Jenkins and every subdomain (staging, admin, monitoring); secure cookie flags are set. See VPS & Server Security Guidelines.
  • Rate limiting/CAPTCHA is active on all authentication endpoints (login, registration, OTP, reset-password, change-password).
  • Token blacklist/revocation store (Redis or equivalent) is provisioned and monitored for the environment.
  • Web and backoffice deployments use distinct signing secrets/keys for tokens.
  • S3/MinIO buckets containing sensitive data are private, with public buckets explicitly reviewed and justified.
  • Service accounts and DB users follow least-privilege access.
  • For étatique/government projects: dependencies are pulled from a self-hosted/offline registry or mirror, not a public registry, and package integrity was verified.
  • Dependabot (or equivalent) is enabled and there are no unresolved critical alerts.
  • Secrets are stored in environment variables or a secret manager — never committed, never baked into images.
  • Security-relevant logs (auth failures, token revocations, admin actions) are centralized and monitored.

11. Professional Guidelines

  • Own your blast radius. If you write it, you are responsible for its security posture in production — not just its functionality.
  • Escalate early, not after an incident. Report suspected vulnerabilities, accidental secret commits, or suspicious activity immediately, regardless of whose code introduced them.
  • No silent workarounds. If a security control (validation, OTP, token check, rate limit) is blocking a delivery deadline, raise it — do not disable or bypass it quietly "temporarily."
  • Treat AI-generated code as untrusted input, per General Engineering Guidelines §13. Review it for the same issues covered in this document before merging.
  • Document security decisions. When a design accepts a risk deliberately (e.g., a relaxed validation rule for a specific reason), record the reasoning in the PR or architecture doc so it isn't mistaken for an oversight later.
  • Least privilege by default. Request only the access you need, for only as long as you need it, whether that's database grants, cloud IAM roles, or admin panel permissions.
  • Continuous vigilance. Security is not a one-time certification (like a SATIM audit) — it is a standing responsibility that applies to every commit, every dependency bump, and every configuration change.
Non-negotiable

Never commit secrets (keys, tokens, passwords, credentials) to the repository. Never disable a security control to "make a deadline" without written sign-off from the security/architecture lead.

Conclusion

These guidelines are the security baseline for everything shipped by Sadeem Informatique, in the same spirit of rigor we apply to SATIM certification. Communicate early, validate everywhere, separate and revoke tokens deliberately, keep production surfaces closed to the public, and treat étatique projects' supply-chain constraints as strict requirements, not suggestions.

Mezaache Akram
Mezaache Akram
Chief Information Security Officer