You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Look I'm not super smart but I updated to 0.2.0 cause i was excited to see if it gets even better than before but its been a rough few hours, suddenly my project refused to compile and it kept complaining that my files are in the internet zone and needs to be unblocked, but they were not. After a long struggle i asked dsh to look into this directly and it thinks it found the issue, here is the output:
[Bug] Windows: the sandbox stamps a Low integrity label on the session workspace, so every file DSH writes is refused by build tools
Summary
On Windows, DSH's ACL sandbox lowers the spawned token to Low integrity and marks the session workspace with the mandatory label Low Mandatory Level:(OI)(CI)(NW). Every file created under that directory inherits the label.
The user-visible effect is that ordinary build tooling (msbuild, dotnet, npm, an editor saving a file) — all Medium integrity — is refused or warned about when it touches those files. Because Low integrity is the level Internet-zone processes run at, this gets misread as a Mark-of-the-Web / "internet zone" problem, which sends you chasing Zone.Identifier streams that do not exist.
The label is applied to whatever directory DSH is launched from, so it follows the user into any project directory they start DSH in.
Environment
Windows 11 (Windows_NT 10.0.26200)
Node.js v26.10.0
@deepseek-ai/dsh 0.2.0-rc.1, launched with dsh web
default permission mode (workspace-write); no DSH_PERMISSION_MODE set
default profile (web)
Reproduction
Launch DSH with a project directory as the working directory:
powershell
cd C:\dev
dsh web
Have DSH (or a tool it runs) create one file in that directory.
Inspect the directory and the new file:
powershell
icacls C:\dev # shows the directory label
icacls C:\dev\new.txt # shows the label inherited by the file
Observed — the directory itself, with (OI)(CI) meaning new children inherit it:
Code block
C:\dev
Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
And a single file written through the sandboxed path, where (I) marks the label as inherited:
Code block
C:\Users<user>.dsh.updater\zone-probe\a.txt :(I)(W,D,DC)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Administrators:(I)(F)
<user>:(I)(F)
Mandatory Label\Low Mandatory Level:(I)(NW)
Note the last line. That is the whole bug: an ordinary text file, created by an ordinary write, carrying a Low integrity mandatory label.
Now build from a normal shell in that directory. Build tooling is refused or warns about the files as untrusted.
Expected behavior
A file DSH writes into the session workspace should be an ordinary file with no mandatory label, exactly as if the user's own shell had written it, so that build tools operating at Medium integrity can rewrite and replace it normally.
Actual behavior
The created entries carry a Low integrity mandatory label and inherit it to everything created beneath them:
Code block
C:\dev Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
C:\Users<user>.dsh Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
C:\Users<user>.dsh\profiles\web
Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
Contrast — directories DSH does not write into are clean, and so are trees written by an unsandboxed install, which is the evidence that this is specifically the sandboxed write path:
Code block
C:\Users<user>\Documents (no Mandatory Label)
C:\Users<user>\Desktop (no Mandatory Label)
C:\Users<user>\AppData\Roaming\npm (no Mandatory Label)
C:\Users<user>\AppData\Roaming\npm\node_modules@deepseek-ai\dsh
(no Mandatory Label)
There is no Zone.Identifier stream on any of these files. A directory-wide scan of the session workspace and the project tree found zero files with a zone tag, so Mark-of-the-Web is not involved.
Root cause
Two shipped pieces combine.
The sandbox lowers the token to Low integrity. In @deepseek-ai/dsh-sandbox-windows-acl, lib/types-*.js documents and implements it:
Code block
Lower the restricted token's integrity level to Low (S-1-16-4096), the level ...
function restrictTokenIntegrity(api, token, lowLabelSidPtr) {
...
api.setTokenInformation(token, 25 /* TokenIntegrityLevel */, info, info.length)
mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'
workspaceRoot: !!js process.cwd()
Because a Low-integrity token creates files with a Low mandatory label, and Windows stamps the label on the directory with (OI)(CI) inheritance, every subsequent write into that directory is tagged — whether it was written by DSH or later by an unrelated tool. Hence "DSH launched from C:\dev" is enough to poison C:\dev for the user's compiler.
I want to be explicit about what I did not verify: whether an earlier runtime does the same thing. I could not compare against 0.1.7-rc.2 after upgrading, but the sandbox lowering the token is deliberate behavior rather than an accident, so I would not expect it to be a 0.2.0-only regression. Someone with two checkouts can settle that in a minute.
Impact
Every file a user asks DSH to create in a directory that is also a build tree becomes unbuildable, which is the main thing many users install DSH to do.
It is silent. Nothing in the UI or logs says a mandatory label was applied, and the natural diagnosis path (Zone.Identifier, "Unblock") leads nowhere.
Cleaning up is per-user and manual: the label has to be cleared from the directory and every file beneath it, and re-running DSH from that directory re-applies it.
It is easy to misattribute to antivirus, Explorer, or the registry ZoneMap\ProtocolDefaults\file value, all of which I checked first and ruled out.
Suggested fix
Whichever of these is acceptable:
Do not lower the token's integrity to Low when a write capability SID is already doing the confinement. If the workspace ACEs are what grant write access, the Low label may be redundant — and it is what makes the artifacts unusable outside DSH.
If Low integrity is required, do not leave the label inheritable on the workspace root. A label that does not carry (OI)(CI), or one applied per file rather than per directory, limits the blast radius to files DSH itself writes.
Failing either, make it visible and documented: a startup warning naming the affected directory, and a documented DSH_PERMISSION_MODE value or config for "do not label the workspace", so users compiling in the same tree have a supported way out.
A per-workspace opt-out is probably the minimum, because "run DSH from the directory you are working in" is the natural usage.
Acceptance criteria
A file created by DSH in the session workspace has no Mandatory Label line in icacls output, matching a file created by the user's own shell in the same directory.
The session workspace directory itself does not carry an inheritable Low mandatory label.
A Medium-integrity build tool can rewrite, replace, and delete a DSH-created file in the workspace without an integrity refusal.
Whatever confinement guarantee the Low label was providing is either preserved by another mechanism or consciously dropped, and the tradeoff is stated in the docs.
Workaround for anyone hitting this
Clearing the label needs LABEL_SECURITY_INFORMATION, which icacls cannot do directly, so it takes a little P/Invoke. This is the version I used — save as strip-low-label.ps1 and run it from a normal PowerShell (elevate only if it reports access denied):
[DllImport("kernel32.dll", SetLastError = true)]
public static extern System.IntPtr LocalFree(System.IntPtr hMem);
public const uint LABEL_SECURITY_INFORMATION = 0x00000010;
public const uint WRITE_OWNER = 0x00080000;
public const uint WRITE_DAC = 0x00040000;
public const int SE_FILE_OBJECT = 1;
/** Clear the mandatory label. Returns 0 on success, otherwise a Win32 error code. */
public static uint ClearLabel(string path) {
System.IntPtr sd;
uint read = GetNamedSecurityInfo(path, SE_FILE_OBJECT,
LABEL_SECURITY_INFORMATION | WRITE_OWNER | WRITE_DAC,
System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero, out sd);
if (read != 0) return read;
if (sd != System.IntPtr.Zero) LocalFree(sd);
return SetNamedSecurityInfo(path, SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION,
System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero);
}
'@
powershell -ExecutionPolicy Bypass -File strip-low-label.ps1 -Path C:\dev -WhatIf # preview
powershell -ExecutionPolicy Bypass -File strip-low-label.ps1 -Path C:\dev # apply
Keep the file pure ASCII — powershell.exe 5.1 reads a BOM-less file as ANSI, and a non-ASCII byte (an em dash, say) turns into a stray quote and produces a misleading Missing closing '}' parse error. I lost time to exactly that.
This is not a fix. DSH re-applies the label the next time it runs with that directory as its workspace. The two durable avoidances are: launch DSH from a directory you do not compile in, or set DSH_PERMISSION_MODE to a mode that does not tag the workspace.
Related #116 — Windows write failure (EISDIR on atomic link) #268 — Windows taskkill lookup crossing the workspace-write boundary, which quotes the same workspaceRoot: process.cwd() default #260 — subprocess spill I/O failure terminating the host
Environment detail: reproduced on 0.2.0-rc.1 with the default web profile. Happy to add diagnostics or test a candidate fix on this machine.
Uhm soo like I said, Probably because I'm an idiot...
Changing the workspace access to "full access" fixes the issue, it only happens with the "write access" it seems.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Look I'm not super smart but I updated to 0.2.0 cause i was excited to see if it gets even better than before but its been a rough few hours, suddenly my project refused to compile and it kept complaining that my files are in the internet zone and needs to be unblocked, but they were not. After a long struggle i asked dsh to look into this directly and it thinks it found the issue, here is the output:
[Bug] Windows: the sandbox stamps a Low integrity label on the session workspace, so every file DSH writes is refused by build tools
Summary
On Windows, DSH's ACL sandbox lowers the spawned token to Low integrity and marks the session workspace with the mandatory label Low Mandatory Level:(OI)(CI)(NW). Every file created under that directory inherits the label.
The user-visible effect is that ordinary build tooling (msbuild, dotnet, npm, an editor saving a file) — all Medium integrity — is refused or warned about when it touches those files. Because Low integrity is the level Internet-zone processes run at, this gets misread as a Mark-of-the-Web / "internet zone" problem, which sends you chasing Zone.Identifier streams that do not exist.
The label is applied to whatever directory DSH is launched from, so it follows the user into any project directory they start DSH in.
Environment
Windows 11 (Windows_NT 10.0.26200)
Node.js v26.10.0
@deepseek-ai/dsh 0.2.0-rc.1, launched with dsh web
default permission mode (workspace-write); no DSH_PERMISSION_MODE set
default profile (web)
Reproduction
Launch DSH with a project directory as the working directory:
powershell
cd C:\dev
dsh web
Have DSH (or a tool it runs) create one file in that directory.
Inspect the directory and the new file:
powershell
icacls C:\dev # shows the directory label
icacls C:\dev\new.txt # shows the label inherited by the file
Observed — the directory itself, with (OI)(CI) meaning new children inherit it:
Code block
C:\dev
Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
And a single file written through the sandboxed path, where (I) marks the label as inherited:
Code block
C:\Users<user>.dsh.updater\zone-probe\a.txt :(I)(W,D,DC)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Administrators:(I)(F)
<user>:(I)(F)
Mandatory Label\Low Mandatory Level:(I)(NW)
Note the last line. That is the whole bug: an ordinary text file, created by an ordinary write, carrying a Low integrity mandatory label.
Now build from a normal shell in that directory. Build tooling is refused or warns about the files as untrusted.
Expected behavior
A file DSH writes into the session workspace should be an ordinary file with no mandatory label, exactly as if the user's own shell had written it, so that build tools operating at Medium integrity can rewrite and replace it normally.
Actual behavior
The created entries carry a Low integrity mandatory label and inherit it to everything created beneath them:
Code block
C:\dev Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
C:\Users<user>.dsh Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
C:\Users<user>.dsh\profiles\web
Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)
Contrast — directories DSH does not write into are clean, and so are trees written by an unsandboxed install, which is the evidence that this is specifically the sandboxed write path:
Code block
C:\Users<user>\Documents (no Mandatory Label)
C:\Users<user>\Desktop (no Mandatory Label)
C:\Users<user>\AppData\Roaming\npm (no Mandatory Label)
C:\Users<user>\AppData\Roaming\npm\node_modules@deepseek-ai\dsh
(no Mandatory Label)
There is no Zone.Identifier stream on any of these files. A directory-wide scan of the session workspace and the project tree found zero files with a zone tag, so Mark-of-the-Web is not involved.
Root cause
Two shipped pieces combine.
Code block
function restrictTokenIntegrity(api, token, lowLabelSidPtr) {
...
api.setTokenInformation(token, 25 /* TokenIntegrityLevel */, info, info.length)
yaml
mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'
workspaceRoot: !!js process.cwd()
Because a Low-integrity token creates files with a Low mandatory label, and Windows stamps the label on the directory with (OI)(CI) inheritance, every subsequent write into that directory is tagged — whether it was written by DSH or later by an unrelated tool. Hence "DSH launched from C:\dev" is enough to poison C:\dev for the user's compiler.
I want to be explicit about what I did not verify: whether an earlier runtime does the same thing. I could not compare against 0.1.7-rc.2 after upgrading, but the sandbox lowering the token is deliberate behavior rather than an accident, so I would not expect it to be a 0.2.0-only regression. Someone with two checkouts can settle that in a minute.
Impact
Every file a user asks DSH to create in a directory that is also a build tree becomes unbuildable, which is the main thing many users install DSH to do.
It is silent. Nothing in the UI or logs says a mandatory label was applied, and the natural diagnosis path (Zone.Identifier, "Unblock") leads nowhere.
Cleaning up is per-user and manual: the label has to be cleared from the directory and every file beneath it, and re-running DSH from that directory re-applies it.
It is easy to misattribute to antivirus, Explorer, or the registry ZoneMap\ProtocolDefaults\file value, all of which I checked first and ruled out.
Suggested fix
Whichever of these is acceptable:
Do not lower the token's integrity to Low when a write capability SID is already doing the confinement. If the workspace ACEs are what grant write access, the Low label may be redundant — and it is what makes the artifacts unusable outside DSH.
If Low integrity is required, do not leave the label inheritable on the workspace root. A label that does not carry (OI)(CI), or one applied per file rather than per directory, limits the blast radius to files DSH itself writes.
Failing either, make it visible and documented: a startup warning naming the affected directory, and a documented DSH_PERMISSION_MODE value or config for "do not label the workspace", so users compiling in the same tree have a supported way out.
A per-workspace opt-out is probably the minimum, because "run DSH from the directory you are working in" is the natural usage.
Acceptance criteria
A file created by DSH in the session workspace has no Mandatory Label line in icacls output, matching a file created by the user's own shell in the same directory.
The session workspace directory itself does not carry an inheritable Low mandatory label.
A Medium-integrity build tool can rewrite, replace, and delete a DSH-created file in the workspace without an integrity refusal.
Whatever confinement guarantee the Low label was providing is either preserved by another mechanism or consciously dropped, and the tradeoff is stated in the docs.
Workaround for anyone hitting this
Clearing the label needs LABEL_SECURITY_INFORMATION, which icacls cannot do directly, so it takes a little P/Invoke. This is the version I used — save as strip-low-label.ps1 and run it from a normal PowerShell (elevate only if it reports access denied):
powershell
strip-low-label.ps1
param([Parameter(Mandatory = $true)][string[]]$Path, [switch]$WhatIf)
$ErrorActionPreference = 'Stop'
Add-Type -Namespace DshLabel -Name Native -MemberDefinition @'
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetNamedSecurityInfo(string pObjectName, int ObjectType, uint SecurityInfo,
System.IntPtr ppsidOwner, System.IntPtr ppsidGroup, System.IntPtr ppDacl, System.IntPtr ppSacl,
out System.IntPtr ppSecurityDescriptor);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern uint SetNamedSecurityInfo(string pObjectName, int ObjectType, uint SecurityInfo,
System.IntPtr psidOwner, System.IntPtr psidGroup, System.IntPtr pDacl, System.IntPtr pSacl);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern System.IntPtr LocalFree(System.IntPtr hMem);
public const uint LABEL_SECURITY_INFORMATION = 0x00000010;
public const uint WRITE_OWNER = 0x00080000;
public const uint WRITE_DAC = 0x00040000;
public const int SE_FILE_OBJECT = 1;
/** Clear the mandatory label. Returns 0 on success, otherwise a Win32 error code. */
public static uint ClearLabel(string path) {
System.IntPtr sd;
uint read = GetNamedSecurityInfo(path, SE_FILE_OBJECT,
LABEL_SECURITY_INFORMATION | WRITE_OWNER | WRITE_DAC,
System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero, out sd);
if (read != 0) return read;
if (sd != System.IntPtr.Zero) LocalFree(sd);
return SetNamedSecurityInfo(path, SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION,
System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero, System.IntPtr.Zero);
}
'@
function Get-LabelText($item) {
$out = & icacls $item 2>&1 | Where-Object { $_ -match 'Mandatory Label' }
if ($null -eq $out) { return $null }
return (($out -join ' ').Trim() -replace '\s+', ' ')
}
$cleared = 0; $failed = 0
foreach ($root in $Path) {
if (-not (Test-Path -LiteralPath $root)) { Write-Host "skip (not found): $root"; continue }
directories first so children stop inheriting, then files
$items = @(Get-Item -LiteralPath $root -Force) +$WhatIf) { Write-Host "would clear: $ ($item.FullName)"; $cleared++; continue }$code): $ ($item.FullName)"; $failed++ }
@(Get-ChildItem -LiteralPath $root -Recurse -Force -ErrorAction SilentlyContinue |
Sort-Object { -not $_.PSIsContainer })
foreach ($item in $items) {
$before = Get-LabelText $item.FullName
if ($null -eq $before -or $before -notmatch 'Low Mandatory Level') { continue }
if (
$code = [DshLabel.Native]::ClearLabel($item.FullName)
if ($code -eq 0) { $cleared++ } else { Write-Host "FAILED (
}
}
Write-Host "cleared: $cleared failed: $failed"
if ($failed -gt 0) { Write-Host 'Re-run from an ELEVATED PowerShell for the failures.'; exit 1 }
Usage:
powershell
powershell -ExecutionPolicy Bypass -File strip-low-label.ps1 -Path C:\dev -WhatIf # preview
powershell -ExecutionPolicy Bypass -File strip-low-label.ps1 -Path C:\dev # apply
Keep the file pure ASCII — powershell.exe 5.1 reads a BOM-less file as ANSI, and a non-ASCII byte (an em dash, say) turns into a stray quote and produces a misleading Missing closing '}' parse error. I lost time to exactly that.
This is not a fix. DSH re-applies the label the next time it runs with that directory as its workspace. The two durable avoidances are: launch DSH from a directory you do not compile in, or set DSH_PERMISSION_MODE to a mode that does not tag the workspace.
Related
#116 — Windows write failure (EISDIR on atomic link)
#268 — Windows taskkill lookup crossing the workspace-write boundary, which quotes the same workspaceRoot: process.cwd() default
#260 — subprocess spill I/O failure terminating the host
Environment detail: reproduced on 0.2.0-rc.1 with the default web profile. Happy to add diagnostics or test a candidate fix on this machine.
All reactions