Security Features

This page catalogues every security control implemented in cloud-share. Each control lists its industry-standard framework reference, the component it applies to, and the threat it addresses.

Frameworks referenced on this page:

AbbreviationStandard
OWASPOWASP Top 10 (2021)
NIST 800-53NIST SP 800-53 Rev. 5 — Security & Privacy Controls
NIST 800-132NIST SP 800-132 — Password-Based Key Derivation
NIST 800-52NIST SP 800-52 Rev. 2 — TLS Guidelines
NIST CSFNIST Cybersecurity Framework 2.0
RFC 5869HKDF — HMAC-based Key Derivation Function
FIPS 197AES — Advanced Encryption Standard
FIPS 198-1HMAC
STRIDESTRIDE Threat Model
CWEMITRE Common Weakness Enumeration

Transit & Cryptography

Controls protecting data as it crosses physical network boundaries.

AES-256-GCM Encryption

PropertyDetail
ComponentCloudShare.Core
StandardFIPS 197 · NIST SP 800-38D · OWASP A02:2021
CWE mitigatedCWE-311 — Missing Encryption of Sensitive Data

All content — text, files, and zip bundles — is encrypted with AES-256-GCM at the application layer before it leaves the sender process. GCM (Galois/Counter Mode) is an authenticated encryption scheme: it provides both confidentiality (content cannot be read) and integrity (any modification to the ciphertext causes decryption to fail).

Each item uses a unique 12-byte random nonce, ensuring identical plaintexts always produce different ciphertexts.


HKDF-SHA256 Key Derivation

PropertyDetail
ComponentCloudShare.Core
StandardRFC 5869 · NIST SP 800-56C Rev. 2 · NIST SP 800-132 · OWASP A02:2021
CWE mitigatedCWE-916 — Use of Password Hash With Insufficient Computational Effort

The AES-256 key is derived from the shared secret using HKDF (HMAC-based Key Derivation Function, RFC 5869) with SHA-256 as the underlying hash. A fixed context binding (cloud-share-v1) is used as the HKDF salt, providing cryptographic domain separation.

flowchart LR
    A["secret\n(12-char alphanumeric)"] --> B["HKDF-SHA256\nsalt: 'cloud-share-v1'"]
    B --> C["32-byte AES-256 key\n(256 bits)"]

This replaces a naive SHA-256(secret) approach, which would not constitute a proper KDF under NIST SP 800-132. HKDF ensures the output key material is indistinguishable from random regardless of the input’s structure.


SHA-512 Integrity Hash

PropertyDetail
ComponentCloudShare.Core
StandardFIPS 198-1 · NIST SP 800-53 SC-8 · STRIDE: Tampering
CWE mitigatedCWE-345 — Insufficient Verification of Data Authenticity

A SHA-512 hash of the plaintext is computed before encryption and stored in the queue item metadata. The receiver independently computes the hash after decryption and compares it to the sender’s value. A mismatch causes the item to be permanently deleted from the sender and the decrypted content to be discarded.

This provides defense-in-depth: the GCM authentication tag verifies ciphertext integrity at the transport layer; SHA-512 provides an independent application-level content integrity check.

⚠️ Warning: A hash mismatch is a strong signal of tampering. In normal operation this should never occur. If you see a mismatch, do not trust the content — restart the sender and re-queue the item.


TLS 1.3 Transport

PropertyDetail
ComponentSender · Receiver
StandardNIST SP 800-52 Rev. 2 · OWASP A02:2021 · STRIDE: Information Disclosure
CWE mitigatedCWE-319 — Cleartext Transmission of Sensitive Information

All traffic traverses Microsoft Dev Tunnels over HTTPS/TLS 1.3 using valid *.devtunnels.ms certificates. The receiver enforces HTTPS-only at startup — providing an HTTP URL is rejected with a validation error before any connection is attempted.


Bearer Token Authentication

PropertyDetail
ComponentSender · Receiver
StandardOWASP A07:2021 · NIST SP 800-53 IA-3 · STRIDE: Information Disclosure
CWE mitigatedCWE-598 — Sensitive Query String in GET Request

The shared session secret is transmitted exclusively via the Authorization: Bearer <token> HTTP header on every API call. It is never placed in URL query strings, path parameters, or JavaScript-accessible cookies. This keeps the secret out of access logs, browser history, proxy logs, Referer headers, and DevTunnels infrastructure logs.


Plaintext Zeroed After Decryption

PropertyDetail
ComponentReceiver
StandardNIST SP 800-53 SC-28 · STRIDE: Information Disclosure
CWE mitigatedCWE-316 — Cleartext Storage of Sensitive Information in Memory

CryptographicOperations.ZeroMemory() is called in a finally block to overwrite all decrypted byte arrays immediately after use. This minimises the window during which sensitive plaintext resides in managed heap memory and reduces exposure in the event of a memory dump or swap file access.


Authentication & Access Control

Controls verifying identity and restricting access to local and remote endpoints.

Sender Web UI Token

PropertyDetail
ComponentSender
StandardOWASP A01:2021 · NIST SP 800-53 AC-3 · STRIDE: Elevation of Privilege
CWE mitigatedCWE-200 — Exposure of Sensitive Information

A dedicated 128-bit random _uiToken (independent of the encryption secret) gates access to the sender web UI. The browser is opened to http://localhost:{port}/?token=<uiToken>. On the first visit the server validates the token, sets an HttpOnly SameSite=Strict cookie, then redirects to /. All subsequent visits are validated against the cookie. Unauthenticated requests receive 401 Unauthorized.

This ensures the HTML page containing the session secret is never served to unauthenticated local processes, browser extensions, or malware.

ℹ️ Info: The UI token and the encryption secret are independent values generated separately. The UI access token never participates in cryptographic operations; the encryption secret is never used as an access control token. This is the principle of key separation (NIST SP 800-53 SC-12).


Receiver Local Session Token

PropertyDetail
ComponentReceiver
StandardOWASP A01:2021 · NIST SP 800-53 AC-3 · STRIDE: Spoofing
CWE mitigatedCWE-306 — Missing Authentication for Critical Function

A 128-bit random localToken is generated at startup and required on all receiver local endpoints. Fetch-based API calls use Authorization: Bearer <localToken>. The EventSource SSE connection (which cannot set custom headers) uses a local_token HttpOnly cookie instead.

Without this token, any process on the same machine — or any website mounting a DNS-rebinding attack — could receive, read, and delete all shared content. All receiver endpoints return 401 Unauthorized without a valid token.


Brute-Force Lockout

PropertyDetail
ComponentSender
StandardOWASP A07:2021 · NIST SP 800-53 AC-7 · STRIDE: Spoofing
CWE mitigatedCWE-307 — Improper Restriction of Excessive Authentication Attempts

After 10 consecutive authentication failures, all sender API endpoints return HTTP 429 Too Many Requests with a Retry-After: 60 header. The lockout lasts 60 seconds. The failure counter is thread-safe (using Interlocked) and resets on any successful authentication. All lockout events are logged as warnings.

  10 failures → 60-second lockout → HTTP 429 + Retry-After header
  

Constant-Time Comparisons

PropertyDetail
ComponentSender · Receiver
StandardOWASP A02:2021 · STRIDE: Information Disclosure
CWE mitigatedCWE-208 — Observable Timing Discrepancy

All secret, token, and hash comparisons use CryptographicOperations.FixedTimeEquals(). Standard string equality short-circuits on the first differing character — an attacker can determine the correct value byte-by-byte by measuring response times. Constant-time comparison always takes the same time regardless of where (or whether) a difference occurs.

This applies to: sender secret comparison, sender UI token comparison, receiver local token comparison, and SHA-512 hash verification.


HTTPS-Only Enforcement

PropertyDetail
ComponentReceiver
StandardOWASP A02:2021 · NIST SP 800-52 Rev. 2
CWE mitigatedCWE-295 — Improper Certificate Validation

The receiver’s NormalizeUrl helper rejects any URL that does not begin with https:// with an explicit validation error: “Only HTTPS URLs are supported.” This prevents accidental use of unencrypted HTTP connections to the sender tunnel, which would expose the secret and all encrypted data to network observers.


Input Validation & Injection Prevention

Controls rejecting malformed or malicious input.

File Size Limits

Item typeLimitEnforcement
Text10 MBApplication-level + Kestrel
File100 MBApplication-level + Kestrel
Zip bundle100 MBApplication-level + Kestrel

The Kestrel web server is configured with MaxRequestBodySize = 110_000_000 (110 MB). This hard limit runs before application code and cannot be bypassed via chunked transfer encoding. Application-level size checks run as a second gate (NIST SP 800-53 SC-5, STRIDE: Denial of Service, CWE-770).


Filename Sanitisation

PropertyDetail
ComponentSender (upload) · Receiver (download)
StandardOWASP A03:2021 · STRIDE: Tampering
CWE mitigatedCWE-22 — Path Traversal · CWE-73 — External Control of File Name

Filenames are sanitised on both sides:

  • Sender: path separators (/, \), null bytes, oversized names, and empty values are stripped or replaced before the filename is stored in queue metadata.
  • Receiver: Path.GetFileName() is applied to the sender-supplied filename regardless of what the sender sends. A compromised sender cannot deliver path-traversal filenames like ../../.bashrc.

Item ID Validation

PropertyDetail
ComponentReceiver
StandardOWASP A03:2021 · STRIDE: Tampering
CWE mitigatedCWE-20 — Improper Input Validation

The {id} route parameter on /receive/{id} and /item/{id} is validated against ^[a-zA-Z0-9_-]{8,64}$ before being forwarded as part of the sender URL. This prevents SSRF-adjacent crafted path injection that could cause the receiver to access unintended sender endpoints.


Exception Details Suppressed

PropertyDetail
ComponentReceiver
StandardOWASP A09:2021 · STRIDE: Information Disclosure
CWE mitigatedCWE-209 — Error Message Containing Sensitive Information

Exceptions caught in proxy endpoints return Results.StatusCode(502) rather than re-throwing. This prevents ASP.NET Core’s developer exception page from leaking stack traces, internal class names, library versions, and file paths to HTTP clients.


Anti-CSRF Protection

Controls preventing cross-site request forgery against local API endpoints.

Origin / Referer Header Validation

PropertyDetail
ComponentSender
StandardOWASP A01:2021 · NIST SP 800-53 SC-8 · STRIDE: Elevation of Privilege
CWE mitigatedCWE-352 — Cross-Site Request Forgery

Every mutating endpoint (POST /upload/text, POST /upload/file, POST /upload/zip, DELETE /item/{id}) validates the Origin or Referer header when present. If the header is present and does not resolve to the sender’s own localhost:<port> origin, the request is rejected with HTTP 403 Forbidden.

API clients (curl, Postman, the receiver) that omit browser-injected headers are not rejected — they are independently protected by Bearer token authentication which browsers cannot automatically include cross-origin.

  Browser request → Origin: https://evil.example.com → HTTP 403 Forbidden
API request     → no Origin/Referer header         → proceed (Bearer token required)
Receiver proxy  → Authorization: Bearer <secret>   → proceed
  

Resource Exhaustion & DoS Prevention

Controls preventing abuse of shared resources.

Rate Limiting (Receiver)

PropertyDetail
ComponentReceiver
StandardNIST SP 800-53 SC-5 · OWASP A04:2021 · STRIDE: Denial of Service
CWE mitigatedCWE-770 — Allocation of Resources Without Limits

The receiver applies a fixed-window rate limiter to all proxied endpoints: a maximum of 30 requests per 10-second window per client. Requests beyond this threshold receive HTTP 429 Too Many Requests. This prevents a compromised sender or rogue local process from flooding the receiver proxy with requests and exhausting socket or memory resources.


Response Size Caps (Receiver)

PropertyDetail
ComponentReceiver
StandardNIST SP 800-53 SC-5 · OWASP A04:2021 · STRIDE: Denial of Service
CWE mitigatedCWE-400 — Uncontrolled Resource Consumption

The receiver enforces hard response-size caps when proxying sender responses:

EndpointCapEnforcement
GET /queue (JSON list)1 MBReadCappedAsync
GET /item/{id} (encrypted content)150 MBReadCappedAsync

ReadCappedAsync checks the Content-Length header first (fast rejection), then streams the response body into a counter. If the cap is exceeded at any point, the operation is aborted, the oversized response is discarded, and HTTP 502 is returned to the browser. Each oversize event is logged with the SECURITY_EVENT: prefix.


SSE Message Validation (Receiver)

PropertyDetail
ComponentReceiver
StandardNIST CSF PR.DS · OWASP A03:2021 · STRIDE: Tampering
CWE mitigatedCWE-20 — Improper Input Validation

The receiver validates every SSE (text/event-stream) message received from the sender before forwarding it to the browser. A line-by-line parser extracts only data: lines and verifies each as valid JSON containing a known type field. Unknown type values and malformed JSON are silently dropped; all other SSE line types (event:, retry:, blank lines) are forwarded without modification.

This prevents a compromised or malicious sender from injecting arbitrary JavaScript or HTML via the event stream that could be executed in the receiver’s browser context.


Zip Aggregate Input Check

PropertyDetail
ComponentSender
StandardNIST SP 800-53 SC-5 · STRIDE: Denial of Service
CWE mitigatedCWE-770 — Allocation of Resources Without Limits

Before creating an in-memory zip archive, the sender sums the sizes of all uploaded files in the multipart request. If the aggregate total exceeds the 100 MB limit, the request is rejected with HTTP 400 before any MemoryStream allocation. This prevents zip-bomb-style attacks where many small files are uploaded to force a large allocation inside the zip-building process.


SSE Connection Limit

PropertyDetail
ComponentSender
StandardNIST SP 800-53 SC-5 · STRIDE: Denial of Service
CWE mitigatedCWE-770 — Allocation of Resources Without Limits

The sender enforces a maximum of 10 concurrent SSE (Server-Sent Events) connections. Requests beyond this limit receive HTTP 429. Each accepted connection uses a bounded Channel<string>(capacity: 100) — slow or unresponsive clients cannot cause unbounded memory growth. Slow writers drop events rather than blocking the broadcaster.


Queue Size Limit

PropertyDetail
ComponentSender
StandardNIST SP 800-53 SC-5 · STRIDE: Denial of Service
CWE mitigatedCWE-770 — Allocation of Resources Without Limits

The in-memory queue is capped at 50 items. Upload attempts when the queue is full return HTTP 429. Each file item can be up to 100 MB of base64-encoded ciphertext in memory (~133 MB per item); without a cap, a malicious authenticated sender could exhaust process memory.


Separate SSE HttpClient

PropertyDetail
ComponentReceiver
StandardNIST CSF PR.DS · STRIDE: Denial of Service
CWE mitigatedCWE-400 — Uncontrolled Resource Consumption

The receiver uses two distinct HttpClient instances:

ClientTimeoutUsed for
http30 secondsAll API calls (/queue, /receive, /item, /delete)
httpSseInfiniteTimeSpanSSE stream (/events) only, managed by CancellationToken

This prevents slow-loris attacks on API calls (30-second hard timeout) while allowing the long-lived SSE connection to remain open indefinitely — which is a requirement of the text/event-stream protocol.


HTTP Security Headers

Headers applied by middleware to every HTTP response from both local servers.

HeaderValueProtection
Content-Security-Policydefault-src 'self' cdn.jsdelivr.net; script-src 'self' cdn.jsdelivr.net 'unsafe-inline'; style-src 'self' cdn.jsdelivr.net 'unsafe-inline'Blocks injection of scripts from unauthorised origins (OWASP A05:2021, CWE-1021)
X-Frame-OptionsDENYPrevents clickjacking via <iframe> embedding (OWASP A05:2021)
X-Content-Type-OptionsnosniffPrevents MIME-sniffing attacks (OWASP A05:2021, CWE-693)
Referrer-Policyno-referrerSuppresses Referer header — prevents local URL leakage to CDN requests (STRIDE: Information Disclosure)

CORS — Localhost-Only Origin

PropertyDetail
ComponentSender · Receiver
StandardOWASP A01:2021 · OWASP A05:2021
CWE mitigatedCWE-942 — Permissive Cross-domain Policy

Both servers apply a strict CORS policy permitting only requests from their own localhost:<port> origin. This blocks DNS-rebinding attacks, where a malicious website temporarily resolves a domain to 127.0.0.1 and then issues cross-origin requests to steal content from the local server.


Secret & Credential Hygiene

Controls preventing unintentional disclosure of secrets and credentials.

Secret Masked in Console

PropertyDetail
ComponentSender
StandardOWASP A09:2021 · NIST SP 800-53 IA-5 · STRIDE: Information Disclosure
CWE mitigatedCWE-532 — Insertion of Sensitive Information into Log File

The secret token is displayed as ****<last-4-chars> in the sender’s startup table by default. The full value is revealed only when the --show-secret flag is passed. This protects against shoulder-surfing, screen recordings, and screenshots inadvertently shared with the secret visible.


Session File Permissions

PropertyDetail
ComponentCloudShare.Core
StandardNIST SP 800-53 AC-3 · AC-6
CWE mitigatedCWE-732 — Incorrect Permission Assignment for Critical Resource

receiver-session.json (which stores the last-used tunnel URL and session secret) is written with chmod 600 (UserRead | UserWrite) on Linux and macOS immediately after creation. This prevents other local accounts from reading saved credentials, which is especially important on shared or multi-user systems.


CLOUDSHARE_SECRET Environment Variable

PropertyDetail
ComponentSender · Receiver
StandardOWASP A09:2021 · NIST SP 800-53 IA-5 · STRIDE: Information Disclosure
CWE mitigatedCWE-214 — Invocation of Process Using Visible Sensitive Information

Both tools read the CLOUDSHARE_SECRET environment variable at startup:

  • Sender: if set, its value overrides the randomly generated secret, allowing scripted or CI sessions to use a known secret without passing it as a command-line flag.
  • Receiver: if set, the interactive startup prompt is skipped entirely — the tool connects immediately without user input.

Using an environment variable keeps the secret out of:

  • The shell history file (.bash_history, .zsh_history)
  • The process argument list (visible to ps aux, Task Manager, and /proc/<pid>/cmdline)
  • Automated build logs where command output is captured
  # Safer than: cloud-share-receiver --secret aB3kP9mQ2rTs
export CLOUDSHARE_SECRET="aB3kP9mQ2rTs"
cloud-share-receiver
  

Key Separation: UI Token vs Encryption Secret

PropertyDetail
ComponentSender
StandardNIST SP 800-53 SC-12 · OWASP A02:2021
CWE mitigatedCWE-321 — Use of Hard-coded Cryptographic Key

The _uiToken (web UI access control) and _secret (AES key material) are independently generated random values that serve entirely different purposes. The UI token is never used in cryptographic operations; the encryption secret is never used as an authentication token. Reusing one value for both purposes would create a transitive secret exposure risk — compromising either value would compromise both functions.


Supply Chain & CI/CD

Controls verifying the integrity of third-party components and the delivery pipeline.

Subresource Integrity (SRI) Hashes

PropertyDetail
ComponentSender · Receiver (web UI)
StandardOWASP A06:2021 · NIST CSF PR.DS · STRIDE: Tampering
CWE mitigatedCWE-494 — Download of Code Without Integrity Check

Every <script> and <link> tag loading a CDN resource carries an integrity= attribute (SRI hash) and crossorigin="anonymous". The browser verifies the cryptographic hash of each downloaded asset before executing or applying it. If the CDN delivers a tampered or substituted file, the browser rejects it outright.

All CDN versions are pinned exactly — no floating @3.x.x wildcards:

ResourceVersionHash algorithm
Bootstrap CSS5.3.8SHA-384
Bootstrap JS bundle5.3.8SHA-384
Bootstrap Icons CSS1.11.3SHA-256
Alpine.js3.15.8SHA-256

Security Event Logging (SECURITY_EVENT:)

PropertyDetail
ComponentSender · Receiver
StandardNIST SP 800-53 AU-2 · NIST CSF DE.AE · OWASP A09:2021
CWE mitigatedCWE-778 — Insufficient Logging of Security-Relevant Events

Security-significant events are prefixed with SECURITY_EVENT: in the console log. This prefix allows log aggregators, SIEM tools, and shell grep queries to reliably identify and alert on security incidents without parsing unstructured text.

Events logged with this prefix include:

EventTrigger
SECURITY_EVENT: Decryption failureAES-GCM auth tag rejected or decryption threw
SECURITY_EVENT: Hash mismatchSHA-512 post-decryption hash does not match sender’s stored hash
SECURITY_EVENT: Response too largeReadCappedAsync exceeded 1 MB (queue) or 150 MB (item)
SECURITY_EVENT: Malformed SSE messageSSE data: line failed JSON parse or contained unknown type
SECURITY_EVENT: Brute-force lockout10 consecutive auth failures triggered 60-second lockout

curl|bash Install Notice (DependencyManager)

PropertyDetail
ComponentCloudShare.Core
StandardOWASP A06:2021 · NIST CSF ID.SC
CWE mitigatedCWE-494 — Download of Code Without Integrity Check

On Linux, the DevTunnels CLI is installed via curl | bash. Before executing this command, DependencyManager prints a security notice reminding users that curl | bash executes remote code without local signature verification, and provides a link to the GitHub releases page for manual SHA-256 verification as an alternative.


Vulnerable Package Scanning

PropertyDetail
ComponentCI/CD
StandardOWASP A06:2021 · NIST CSF ID.RA · NIST SP 800-53 SA-11
CWE mitigatedCWE-1104 — Use of Unmaintained Third Party Components

Every CI build runs dotnet list package --vulnerable --include-transitive. If any direct or transitive NuGet dependency has a known CVE, the build step fails and the issue must be resolved before the pipeline can continue.


Dependabot — Automated Dependency Updates

PropertyDetail
ComponentCI/CD
StandardOWASP A06:2021 · NIST CSF ID.RA-1
CWE mitigatedCWE-1104 — Use of Unmaintained Third Party Components

.github/dependabot.yml is configured for weekly NuGet dependency scanning. GitHub Dependabot automatically raises pull requests when outdated or vulnerable packages are detected, ensuring the dependency tree stays current without manual monitoring.


Summary

CategoryControls
Transit & CryptographyAES-256-GCM · HKDF-SHA256 · SHA-512 hash · TLS 1.3 · Bearer auth · Memory zeroing
Authentication & Access ControlUI token · Local session token · Brute-force lockout · Constant-time comparisons · HTTPS-only
Anti-CSRFOrigin/Referer header validation (HTTP 403)
Input ValidationFile size limits · Kestrel body limit · Filename sanitisation (×2) · ID validation · Error suppression · Zip aggregate input check
Resource & DoS ProtectionSSE connection limit · Queue size limit · Split SSE/API HttpClients · Rate limiting (30 req/10s) · Response size caps (1MB/150MB) · SSE message validation
HTTP Security HeadersCSP · X-Frame-Options · X-Content-Type-Options · Referrer-Policy · CORS
Secret & Credential HygieneConsole masking · Session file permissions · Key separation · CLOUDSHARE_SECRET env var
Supply Chain & CI/CDVulnerable package scan · Dependabot · SRI hashes (CDN) · curl|bash notice
ObservabilitySECURITY_EVENT: structured logging prefix
Total controls41

See also: Encryption Architecture for the full cryptographic flow, and Best Practices for operational guidance.