Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.261.313"
VERSION = "0.261.314"
IS_DEVELOPMENT = is_development_env_enabled()

# Opt-out for deployments where App Service Easy Auth is active but the platform
Expand Down
9 changes: 9 additions & 0 deletions application/single_app/functions_azure_endpoint_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
"Queue Storage actions require an HTTPS Azure Queue service endpoint such as "
"https://account.queue.core.windows.net"
)
AZURE_FILE_ENDPOINT_ERROR = (
"Azure Files sources require an HTTPS Azure File service endpoint such as "
"https://account.file.core.windows.net"

Check warning on line 91 in application/single_app/functions_azure_endpoint_validation.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains external connection or remote asset marker. Recommendation%3A Review whether changed code can send prompts, files, credentials, cookies, settings, logs, or user data to a new sink.
)
AZURE_COSMOS_ENDPOINT_ERROR = (
"Cosmos actions require an HTTPS Azure Cosmos DB endpoint such as "
"https://account.documents.azure.com"
Expand Down Expand Up @@ -243,6 +247,11 @@
return _validate_storage_endpoint(value, AZURE_QUEUE_SERVICE_LABEL, AZURE_QUEUE_ENDPOINT_ERROR)


def validate_azure_file_endpoint(value: Any) -> str:

Check warning on line 250 in application/single_app/functions_azure_endpoint_validation.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
"""Return a canonical Azure File service origin, or raise ValueError."""
return _validate_storage_endpoint(value, AZURE_FILE_SERVICE_LABEL, AZURE_FILE_ENDPOINT_ERROR)

Check warning on line 252 in application/single_app/functions_azure_endpoint_validation.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.

Check warning on line 252 in application/single_app/functions_azure_endpoint_validation.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.


def validate_azure_cosmos_endpoint(value: Any) -> str:
"""Return a canonical Azure Cosmos DB origin, or raise ValueError."""
_, hostname = parse_azure_https_endpoint(
Expand Down
11 changes: 6 additions & 5 deletions application/single_app/functions_file_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from functions_azure_endpoint_validation import (
AZURE_STORAGE_ENDPOINT_SUFFIXES,
azure_storage_endpoint_suffix_for_hostname,
validate_azure_file_endpoint,

Check warning on line 48 in application/single_app/functions_file_sync.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
)
from functions_debug import debug_print
from functions_documents import (
Expand Down Expand Up @@ -892,12 +893,10 @@
if "://" not in raw_url:
raw_url = f"https://{raw_url}"

account_url = validate_azure_file_endpoint(raw_url)

Check warning on line 896 in application/single_app/functions_file_sync.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
parsed_url = urlparse(raw_url)
if parsed_url.scheme != "https" or not parsed_url.netloc:
raise ValueError("Azure Files sources require an HTTPS file service or share URL")

path_parts = [unquote(path_part) for path_part in parsed_url.path.split("/") if path_part]
return f"{parsed_url.scheme}://{parsed_url.netloc}".rstrip("/"), path_parts
return account_url, path_parts


def _normalize_azure_share_name(value: Any) -> str:
Expand Down Expand Up @@ -3253,9 +3252,11 @@
raise ValueError("Azure Files connection string authentication requires a connection string")
return ShareServiceClient.from_connection_string(connection_string)

account_url = connection.get("account_url") or ""
account_url, account_path_parts = _normalize_azure_file_url(connection.get("account_url"))
if not account_url:
raise ValueError("Azure Files source is missing an account URL")
if account_path_parts:
raise ValueError("Azure Files source account URL must be a service URL")
if auth_type == "client_secret":
client_id = auth.get("identity") or ""
client_secret = _resolved_auth_secret(auth)
Expand Down
29 changes: 28 additions & 1 deletion docs/explanation/features/v0.241.127/AZURE_FILES_FILE_SYNC.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

Implemented in version: **0.241.127**

Endpoint validation updated in version: **0.261.314**

## Dependencies

- `azure-storage-file-share==12.25.0`
Expand All @@ -24,6 +26,25 @@

SMB sources continue to support username/password and anonymous authentication for UNC paths.

### Approved endpoints

From version **0.261.314**, the File service URL must use a canonical Azure
Files hostname: `account.file.core.windows.net`,
`account.file.core.usgovcloudapi.net`, `account.file.core.chinacloudapi.cn`, or
`account.file.core.cloudapi.de`. A share URL such as
`https://account.file.core.windows.net/documents/team` supplies the share and

Check warning on line 35 in docs/explanation/features/v0.241.127/AZURE_FILES_FILE_SYNC.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains external connection or remote asset marker. Recommendation%3A Review whether changed code can send prompts, files, credentials, cookies, settings, logs, or user data to a new sink.
optional directory when those fields are not already provided.

The server rejects arbitrary hosts, IP addresses, embedded credentials,

Check warning on line 38 in docs/explanation/features/v0.241.127/AZURE_FILES_FILE_SYNC.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
explicit ports, queries, and fragments, and revalidates saved account URLs

Check warning on line 39 in docs/explanation/features/v0.241.127/AZURE_FILES_FILE_SYNC.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
before token-authenticated SDK construction. Private endpoints should use the

Check warning on line 40 in docs/explanation/features/v0.241.127/AZURE_FILES_FILE_SYNC.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
canonical account hostname with private DNS. Custom domains, direct private-link
hostnames, and emulator URLs are not accepted in the URL field.
Connection-string credential dispatch is unchanged.

See [File Sync SSRF endpoint validation](../../fixes/FILE_SYNC_SSRF_ENDPOINT_VALIDATION_FIX.md)
for the security boundary and compatibility details.

## Usage Instructions

Admins can enable Azure Files in Admin Settings under File Sync source type visibility. Workspace managers then choose Azure Files in the Add Source workflow, enter the file service or share URL, share name, and directory path, and select a compatible reusable identity or source-local Azure Files credential.
Expand All @@ -33,7 +54,13 @@
## Testing and Validation

- Functional coverage: `functional_tests/test_file_sync_azure_files_identity.py`
- Endpoint and OneDrive path regression coverage: `functional_tests/test_file_sync_ssrf_validation.py`
- Existing File Sync capability coverage: `functional_tests/test_file_sync_capability.py`
- UI coverage updated for source type visibility and Azure Files source modal rendering

Known limitation: PIV/smart-card authentication is not implemented inside the web app. PIV and smart-card flows belong at the client or domain/Kerberos layer for SMB access; SimpleChat can consume the resulting SMB path through the existing SMB connector.
Known limitation: PIV/smart-card authentication is not implemented inside the web app. PIV and smart-card flows belong at the client or domain/Kerberos layer for SMB access; SimpleChat can consume the resulting SMB path through the existing SMB connector.

Known limitation: the pinned Azure Files SDK requires `token_intent` for token
credentials, but the current connector does not supply it. Managed-identity and
service-principal client construction therefore fails before network access.
The endpoint validation change does not repair this separate authentication issue.
123 changes: 123 additions & 0 deletions docs/explanation/fixes/FILE_SYNC_SSRF_ENDPOINT_VALIDATION_FIX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# File Sync SSRF Endpoint Validation Fix

Fixed in version: **0.261.314**

Related code-scanning alerts: [1090](https://github.com/microsoft/simplechat/security/code-scanning/1090)
and [2098](https://github.com/microsoft/simplechat/security/code-scanning/2098), both
`py/partial-ssrf`.

## Issue description and root cause

Azure Files connection normalization previously required only an HTTPS scheme
and a nonempty authority. Arbitrary hosts could consequently reach the
`ShareServiceClient` constructor with the application's managed identity or a
service-principal credential. Validating a URL's syntax alone does not establish
that its destination is an approved Azure service.

The pinned `azure-storage-file-share==12.25.0` SDK currently rejects the affected
token-credential construction because it does not supply `token_intent`.
Investigation did not establish a network request or token disclosure through
that call. This incidental SDK failure is not a durable endpoint security
boundary: fixing authentication separately must not enable arbitrary destinations.
This change does not repair that authentication failure.

The OneDrive flow reported by alert 1090 already normalizes selected paths,
rejects traversal segments, and percent-encodes each segment beneath a user's
Graph drive path. The reported browse-path input cannot change the Graph origin.
No OneDrive runtime change or alert suppression is included.

## Technical details

### Files modified

- `application/single_app/functions_azure_endpoint_validation.py`
- `application/single_app/functions_file_sync.py`
- `application/single_app/config.py`
- `functional_tests/test_file_sync_ssrf_validation.py`
- [Azure Files feature documentation](../features/v0.241.127/AZURE_FILES_FILE_SYNC.md)
- [File Sync guide](../../guides/create-a-file-sync.md)

### Endpoint policy

The shared `validate_azure_file_endpoint()` validator requires the `file` service
label, a valid 3-24 character alphanumeric storage account name, and a supported
Azure Storage suffix:

| Cloud | File service hostname |
| --- | --- |
| Public | `account.file.core.windows.net` |
| US Government | `account.file.core.usgovcloudapi.net` |
| China | `account.file.core.chinacloudapi.cn` |
| Germany | `account.file.core.cloudapi.de` |

The validator rejects arbitrary hosts, IP literals, localhost, embedded
credentials, explicit ports (including 443), query strings, fragments,
parameters, unsupported suffixes, and suffix lookalikes. It reconstructs the
HTTPS origin from the validated account name and suffix rather than passing
through the submitted authority.

Service URLs, share URLs, and bare canonical hostnames remain accepted during
configuration. Share and directory components are decoded and normalized as
before. Stored account URLs are revalidated before token-credential and SDK
construction and must not contain a share or directory path.

### Impact and limitations

Existing sources using canonical Azure File service hostnames remain valid.
Private endpoints should use those same hostnames with private DNS resolution.
Custom domains, Azure Stack/custom suffixes, direct private-link hostnames, and
emulator URLs are rejected for the URL field.

Connection-string authentication remains unchanged: it uses the supplied
storage credentials, not the alerted token-credential account URL path. This
fix is not a review of all connection-string endpoints or all File Sync
providers.

OneDrive's absolute Graph pagination links and file-download redirects are not
redesigned by this fix. The regression tests address the reported browse-path
flow, not every possible Graph network interaction.

## Testing and validation

`functional_tests/test_file_sync_ssrf_validation.py` executes the production
normalization, SDK-boundary, Graph-path, and browse-dispatch functions using the
existing isolated function loader. External credentials, SDK construction,
source authorization setup, and HTTP are mocked; no Azure or Cosmos bootstrap
or live network access is required.

Coverage includes accepted endpoints for each supported cloud, decoded
share/directory paths, retained selections, hostile submitted and persisted
URLs, rejection before credential/client construction, canonical SDK inputs,
and unchanged connection-string dispatch. OneDrive tests prepare the outgoing
HTTP URL and verify the configured public/Government Graph origin and user path
are preserved for delimiter-bearing, encoded, and attacker-like browse paths;
invalid segments fail before HTTP.

The application version in `config.py` is incremented to `0.261.314`. The new
test uses a minimum-version assertion so subsequent version bumps do not break
this regression coverage.

Before the change, arbitrary HTTPS Azure Files origins passed normalization.
After the change, they fail at configuration and token-client boundaries.
OneDrive's already-protected browse behavior is unchanged.

Passing local regression tests does not establish CodeQL alert closure. A fresh
GitHub analysis must determine whether either alert remains; neither alert is
automatically dismissed.

### Local results

| Command | Result |
| --- | --- |
| `python -m pytest functional_tests\test_file_sync_ssrf_validation.py functional_tests\test_file_sync_azure_files_identity.py functional_tests\test_file_sync_azure_blob_storage.py functional_tests\test_file_sync_onedrive_personal.py -q` | 166 passed, 1 pre-existing failure |
| Same provider command with `-k "not test_file_sync_routes_do_not_disclose_exception_details"` | 166 passed, 1 deselected |
| `python -m pytest functional_tests\test_action_app_identity_endpoint_hardening.py -q -k "endpoint_allowlist or file_sync_reuses_the_shared_allowlist"` | 3 passed, 7 deselected |
| `python functional_tests\test_docs_app_surface_coverage.py` | 7 checks passed; inventory current |
| `python functional_tests\test_docs_site_quality.py` | 6 checks passed |

The pre-existing failure is
`test_file_sync_routes_do_not_disclose_exception_details`: it expects the old
`[FileSync] Request failed.` tag, while the unchanged route uses
`[FILE_SYNC] Request failed.`. The same failure occurred before the fix
(31 passed, 1 failed). No unrelated logging or test assertion was changed.
The new security regression cases all passed.
18 changes: 18 additions & 0 deletions docs/guides/create-a-file-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ separate workflow; the source editor selects an existing eligible identity.

The source appears in the Sync list. Imported files later appear on the workspace **Documents** tab with fixed or folder tags.

## Azure Files endpoint requirements

From version **0.261.314**, use a canonical Azure Files URL such as
`https://account.file.core.windows.net` or a share URL such as
`https://account.file.core.windows.net/documents/team`. US Government, China,
and Germany endpoints use `core.usgovcloudapi.net`, `core.chinacloudapi.cn`,
and `core.cloudapi.de` respectively after the `account.file.` prefix.

Do not include credentials, an explicit port, a query string, or a fragment in
the URL. Arbitrary domains, IP addresses, and direct private-link hostnames are
not accepted; private endpoints should resolve the canonical account hostname
through private DNS.

Endpoint validation does not repair the separate token-authentication
limitation: the current connector's managed-identity and service-principal
client construction is rejected by the pinned Azure Files SDK. Connection-string
dispatch remains unchanged.

## Troubleshooting

| Symptom | Likely cause | Fix |
Expand Down
Loading
Loading