Markdown Editor

Secure Coding Standard Template

Secure coding rules by area with do/don't code examples, SAST/DAST/secret scanning tooling and an exceptions process

सॉफ़्टवेयर और इंजीनियरिंगमानकsecurecodingstandard
एडिटर में खोलें.md डाउनलोड करें

उपयोग कैसे करें: Use to set the minimum secure coding rules for a team or organisation. Fill scope and languages first, then replace the examples with code from your own stack. The main pitfall is rules that no tool or reviewer checks; map each rule area to a tool in the tooling section.

प्रीव्यू

Secure Coding Standard: [Organisation or product]

Secure coding standard for application developers: scope and languages, mandatory rules by area (input validation, output encoding, authentication, session management, access control, cryptography, secrets, error handling and logging, dependency use, file handling, API security) with do and don't code examples, required tooling (SAST, DAST, secret scanning) and an exceptions process. The areas reflect widely used OWASP concepts (for example the OWASP Top 10 and ASVS topics); the rules and examples are original. Replace every [bracketed] value and adapt examples to your stack.

FieldValue
Document ID[SCS-STD-001]
Version[1.0]
Status[Draft / In review / Approved]
Owner[@appsec-lead]
Approvers[@engineering-director], [@ciso]
Applies to[All production code in repositories under github.com/[org]]
Effective dateYYYY-MM-DD
Next reviewYYYY-MM-DD

1. Purpose and scope

This standard defines the minimum secure coding rules for software written or maintained by [Organisation]. It applies to production code, infrastructure as code and build scripts. Prototypes that never handle real data are exempt until they are promoted.

Language / stackFrameworksExample section owner
Example: TypeScript (Node.js 22 LTS)Express, React[@web-guild]
Example: Python 3.12FastAPI, SQLAlchemy[@python-guild]
Example: Go 1.23net/http, sqlc[@platform]
[Language][Frameworks][@owner]

Rule keywords: MUST is mandatory and enforced in review; SHOULD is expected unless a documented reason applies.

2. Input validation

IDRule
IV-01Input from any source outside the process (HTTP, queues, files, environment) MUST be validated on the server against a schema.
IV-02Validation MUST use allow-lists (expected type, length, pattern, range), not block-lists of bad characters.
IV-03Unexpected fields SHOULD be rejected, and MUST NOT be bound automatically to internal objects (mass assignment).

Do:

import { z } from "zod";
const CreateOrder = z.object({
  sku: z.string().regex(/^[A-Z0-9-]{3,32}$/),
  quantity: z.number().int().min(1).max(999),
}).strict(); // rejects unknown fields
const input = CreateOrder.parse(req.body);

Don't:

// Trusts every field the client sends, including "price" and "isAdmin"
const order = await db.order.create({ data: req.body });

3. Output encoding and injection prevention

IDRule
OE-01Database queries MUST use parameterised statements or a query builder; string concatenation of input into queries is forbidden.
OE-02HTML output MUST be encoded by the template engine; raw HTML insertion requires sanitisation with an approved library.
OE-03Operating system commands MUST NOT be built from input; use library calls or argument arrays without a shell.
OE-04Dynamic code execution (eval, Function, expression languages) MUST NOT process input.

Do:

cur.execute("SELECT id, total FROM orders WHERE customer_id = %s", (customer_id,))
subprocess.run(["convert", src_path, dst_path], check=True)  # no shell

Don't:

cur.execute(f"SELECT * FROM orders WHERE customer_id = '{customer_id}'")
os.system("convert " + filename + " out.png")

4. Authentication

IDRule
AU-01User authentication MUST go through [corporate IdP via OIDC]; custom login forms are not permitted for staff applications.
AU-02Where local passwords are unavoidable they MUST be hashed with [Argon2id] using library defaults or stronger, never with fast hashes.
AU-03Login, recovery and MFA endpoints MUST be rate limited and return the same response for unknown and known accounts.
AU-04Service-to-service calls MUST authenticate with workload identity or short-lived tokens, not shared static passwords.

Do:

from argon2 import PasswordHasher
ph = PasswordHasher()
stored = ph.hash(password)
ph.verify(stored, attempt)

Don't:

stored = hashlib.md5(password.encode()).hexdigest()

5. Session management

IDRule
SE-01Session cookies MUST set Secure, HttpOnly and SameSite=Lax or Strict, and SHOULD use the __Host- prefix.
SE-02Session identifiers MUST be regenerated after login and after privilege change.
SE-03Logout MUST invalidate the session on the server, not only delete the cookie.
SE-04Browser applications SHOULD NOT keep access or refresh tokens in localStorage.

Do:

res.cookie("__Host-sid", sessionId, {
  secure: true, httpOnly: true, sameSite: "lax", path: "/", maxAge: 30 * 60 * 1000,
});

Don't:

localStorage.setItem("refreshToken", token); // readable by any injected script

6. Access control

IDRule
AC-01Every endpoint MUST perform an authorization check on the server; the default MUST be deny.
AC-02Object access MUST verify the caller's relationship to the specific record (ownership, tenant, role), not only that the caller is logged in.
AC-03Authorization logic SHOULD live in one shared module or policy engine, not repeated per handler.

Do:

order, err := store.GetOrder(ctx, orderID)
if err != nil || order.TenantID != caller.TenantID {
    http.NotFound(w, r) // do not reveal existence
    return
}

Don't:

order, _ := store.GetOrder(ctx, r.URL.Query().Get("id")) // any logged-in user, any order

7. Cryptography

IDRule
CR-01Only algorithms on the approved list MUST be used: [AES-256-GCM, ChaCha20-Poly1305, SHA-256 or stronger, Ed25519, ECDSA P-256, RSA 3072+].
CR-02ECB mode, MD5 and SHA-1 for security purposes, and home-made schemes MUST NOT be used.
CR-03Random values for tokens, keys and IDs MUST come from a cryptographically secure generator.
CR-04Keys MUST be managed in [KMS / HSM]; application code receives handles or data keys, never master keys.

Do:

import { randomBytes } from "node:crypto";
const resetToken = randomBytes(32).toString("base64url");

Don't:

const resetToken = Math.random().toString(36).slice(2); // predictable

8. Secrets

IDRule
SK-01Secrets MUST NOT be committed to repositories, including tests and history; secret scanning with push protection MUST be enabled.
SK-02Applications MUST read secrets at runtime from [secrets manager]; container images MUST NOT contain secrets.
SK-03A leaked secret MUST be revoked and rotated within [4 hours]; deleting the commit is not sufficient.

Do:

db_password = secrets_client.get_secret_value(SecretId="prod/payments/db")["SecretString"]

Don't:

DB_PASSWORD = "Summer2026!"  # in source, in history, in every clone

9. Error handling and logging

IDRule
EL-01Errors returned to clients MUST be generic and carry a correlation ID; stack traces and queries MUST NOT reach clients.
EL-02Security events (login success and failure, access denied, privilege change, data export) MUST be logged with who, what, when and from where.
EL-03Logs MUST NOT contain passwords, tokens, full card numbers or unnecessary personal data.
EL-04Log entries built from input MUST be structured (JSON fields), not concatenated strings, to prevent log injection.
EL-05On error in a security check the code MUST deny access (fail closed).

Do:

logger.warn({ event: "authz_denied", userId, resource: "order", orderId, requestId });
res.status(404).json({ type: "about:blank", title: "Not found", requestId });

Don't:

logger.info("Login for " + req.body.email + " with password " + req.body.password);
res.status(500).send(err.stack);

10. Dependency use

IDRule
DE-01New dependencies MUST pass the intake review in [link to intake process].
DE-02Lockfiles MUST be committed and CI MUST install from them.
DE-03Dependencies with known critical or high vulnerabilities MUST be updated within [7 / 30] days or covered by an exception.
DE-04CI actions and base images SHOULD be pinned by commit SHA or digest.

Do:

- uses: actions/checkout@<full-40-character-commit-sha>  # v4.2.2
- run: npm ci

Don't:

- uses: some-org/deploy-action@main
- run: npm install

11. File handling

IDRule
FH-01Uploads MUST be limited in size and validated by content (magic bytes), not only by extension or client content type.
FH-02Stored files MUST use server-generated names; user-supplied paths MUST NOT reach file system calls.
FH-03Archives MUST be extracted with checks against path traversal and decompression bombs.
FH-04Downloads of user files SHOULD be served with Content-Disposition: attachment and X-Content-Type-Options: nosniff.

Do:

safe_name = f"{uuid4()}.pdf"
dest = (UPLOAD_ROOT / safe_name).resolve()
assert dest.is_relative_to(UPLOAD_ROOT)

Don't:

open(os.path.join("/srv/uploads", request.args["name"]), "wb").write(data)  # ../../etc

12. API security

IDRule
AP-01Every API MUST have an OpenAPI or GraphQL schema that is enforced at runtime.
AP-02Responses MUST return only the fields the client needs; internal fields MUST be excluded by an explicit response model.
AP-03APIs MUST apply rate limits per client and limits on page size, query depth and request body size.
AP-04CORS MUST allow only named origins; wildcard origins with credentials are forbidden.
AP-05Server-side requests to user-supplied URLs MUST go through an allow-list and block internal address ranges.

Do:

class OrderOut(BaseModel):
    id: str
    status: str
    total: Decimal  # no internal cost, no customer email

@app.get("/orders/{order_id}", response_model=OrderOut)

Don't:

@app.get("/orders/{order_id}")
def get_order(order_id: str):
    return db.query(Order).get(order_id).__dict__  # every column, every tenant

13. Tooling and verification

Tool typeToolRunsBlocking thresholdRules covered
SASTExample: CodeQL, Semgrep with org rulesetEvery pull requestNew high or critical findingIV, OE, CR, FH
Secret scanningExample: Platform secret scanning with push protection; gitleaks in CIEvery pushAny verified secretSK
Dependency scanning (SCA)Example: Dependabot alerts, OSV-ScannerDaily and on PRCritical or high with fix availableDE
DASTExample: OWASP ZAP baseline scanNightly on stagingHigh alertsSE, AP, EL
Infrastructure as code scanning[Tool]Every PR[Threshold][Rules]
Code review checklistPull request templateEvery PRReviewer sign-offAll

Coverage target: [100%] of production repositories run SAST, secret scanning and SCA by YYYY-MM-DD.

14. Exceptions process

A team that cannot meet a MUST rule requests an exception before merge:

  1. Open a ticket in [SEC project] with the rule ID, the code location, the reason and the compensating controls.
  2. The application security team assesses risk within [5 business days].
  3. Approval authority: Medium risk by [@appsec-lead]; High risk by [@ciso].
  4. Approved exceptions are recorded in the register below, linked from a code comment at the location, and expire after at most [6 months].
IDRuleRepository / locationReasonCompensating controlApproved byExpires
EX-001Example: CR-02legacy-sync/hash.pyPartner API requires SHA-1 HMACIsolated service, partner IP allow-list, migration planned[@appsec-lead]YYYY-MM-DD
[EX-nnn][Rule][Location][Reason][Control][@name]YYYY-MM-DD

15. Training and review

New developers complete [secure coding training] within 30 days of joining and yearly afterwards. Compliance is measured quarterly by [open SAST findings per repository, exceptions past expiry, and the share of repositories with all required tools]. The standard owner reviews this document yearly and after any incident caused by a coding weakness.

Standard and licence note

Based on common industry practice for secure coding and on widely used OWASP concepts, such as the risk areas of the OWASP Top 10 and the topic areas of the OWASP Application Security Verification Standard. No OWASP text is reproduced; the rules, IDs and code examples are original and written for this collection. Consult OWASP resources (owasp.org) for detailed guidance. Template licence: MIT.

संबंधित टेम्पलेट