Repository navigation
Releases: nlink-jp/image-forge
Release list
v0.29.2
v0.29.1
Security
- Whether an input image exists no longer changes the answer. An
init,
mask,controlor upscaleinputthat is a.env, lies in this server's
own directories (a workspace can contain them:work_dir=~/.localwith
workspace_id=share), or is where a link directly inside a credential directory
points was refused when the file was there and answeredinput_not_found
when it was not, so the answer told the caller which of them exist. It is
now judged before anything looks for it (ADR-0010, amendment). Raw LoRA,
ControlNet and hires model paths were already judged first; tests now pin
that, through the renderer's answer too.
v0.29.0
Changed
- Path judgement moved to nlink-jp/pathguard
(ADR-0010).internal/mcp/workdiris now an adapter onto it; the MCP server
wires its guards in one place,mcpGuards. Places
are compared by file identity and by names folded the way the disk folds
them, instead of by name. - A
work_diris now refused in this server's config directory
(~/.config/image-forge, or the$XDG_CONFIG_HOMEform — a config file set
elsewhere withIMAGE_FORGE_CONFIGprotects the file, not the directory it
sits in), in the models directory whenmodels_dirmoves it
outside the data directory, in the real places under your home from
the list gem-agent and lagent use (newly~/.kube,~/.config/gh,~/.azure,
~/.terraform.d,~/.gemini,~/.config/mcp-bridge,~/.netrc,~/.npmrc,
~/.pypirc,~/.git-credentials,~/.vault-token,~/.docker/config.json,
~/.claude.json,~/.bash_history,~/.zsh_history), under every spelling of
any refused place, wherever a link directly inside one of those directories
points (a~/.ssh/configthat links into a sync folder protects the file it
points at), in the account's own home too when$HOMEnames another, and
whenever the home directory cannot be determined.work_dir_deniedcarries
reasonin itsdetails. - A relative
XDG_DATA_HOMEis ignored, as the XDG spec says; it put the data
directory under the working directory. Other relative server directories — a
relativeIMAGE_FORGE_HOME,IMAGE_FORGE_MODELS_DIRormodels_dir, or an
unsetHOME— now make every MCP call fail withwork_dir_deniednaming the
path, rather than protecting nothing; give them absolute paths. A relative
XDG_CONFIG_HOMEis ignored likeXDG_DATA_HOME, and a relative
IMAGE_FORGE_CONFIGis judged from the working directory, as it is read.
Security
- Raw LoRA, ControlNet and hires model paths from MCP are judged. They are
read wherever they lie and were not checked at all, so a credential file
could be loaded as a LoRA. One in a credential or agent-control location, in
this server's config file or directory or the legacy config file in the data
directory (which may holdhf_token), a.envfile, or
a path holding a NUL byte (C stops at it) is now refused with
path_not_allowedbefore the render — and before anything stats it, so a
refusal does not say whether the file exists. An installed name is resolved by
the registry, as before, and is not judged as a path. The CLI and the GUI's
serveloop are unchanged. A workspace input (init,mask,control,
input) that resolves into one of this server's own directories is refused
too: a workspace may contain one (work_dir=~/.local,workspace_id=share). - The workspace directory is judged, not only
work_dir.work_dir=~/.config
withworkspace_id=ghmade the workspace~/.config/gh, a credential
directory; PNGs were written into it and workspace-relative inputs read from
it.<work_dir>/<workspace_id>is now refused withwork_dir_deniedwherever
work_diritself would be. The hole was present since the work-directory
contract (ADR-0009).
Tests
TestWorkDirComesFromRequestMetawaits for its job; returning first raced the
removal of the temporary directory the job writes into.
v0.28.0
v0.27.0
Fixed
-
anima-turboreported the wrong licence, and said commercial use was permitted. The entry carried NVIDIA's Open Model License — the terms of the Cosmos base model Anima was trained from — while the weights it downloads are published by CircleStone Labs under their Non-Commercial License v1.2: non-commercial and non-production use only, with revenue-generating use requiring a licence from them (generated outputs may still be used commercially, §2.e). It is now reported as that, flaggednon-commercial, and carries the attribution notice the licence requires. A test pinned the old flags, so the mistake had a guard holding it in place.If you pulled
anima-turboand relied on whatmodels listsaid about it, this is the entry to re-read. -
A licence correction now reaches an already-installed model.
models listtook the licence recorded in the registry at install time and consulted the catalog only when it was empty, so a model pulled before a correction kept reporting the old terms beside corrected flags. -
controlnet-canny-sd15is reported as OpenRAIL, which is whatlllyasviel/ControlNet-v1-1declares, rather than CreativeML OpenRAIL-M (a different licence). -
illustrious-xl-v1now states that the Hugging Face card for those weights declaresother/sdxl-licensewhile the Civitai listing states no derivatives and credit required. Both exist; the stricter is reported. -
make verify-releasefails closed. Its last block ended a chain of unzip /--version/spctlin|| true, so a zip that did not unpack exited 0 and the upload proceeded.
Added
license_sourceon every catalog entry, surfaced inmodels list --json. It names the card or listing the licence was read from — which for most entries is not the repository the bytes come from, since they download from a quantization or mirror repo. Verified against the publishers on 2026-09-21 and pinned per entry by a test that also compares the entry count, so a model cannot be added without stating where its terms came from.
Apple Silicon only (CGO + Metal). Full notes: CHANGELOG.md
v0.26.5
Security
- A symlink planted at
<work_dir>/<workspace_id>no longer redirects the
whole workspace.os.Rootconfines operations inside a root but resolves
the root path itself normally, so if anything else with write access to your
work directory (another tool, sandboxed code) left a link at the workspace's
name, every read and write anchored on the link's target: images were written
outside the directory you named and the call reported success. The workspace
directory is now created through anos.Rootonwork_dirand then verified
by real path; a workspace whose name resolves elsewhere is refused with
path_not_allowed, naming the id and what it resolved to. - A symlink planted at the engine's temp output path is no longer written
through.generateandupscalehand the diffusion engine an absolute
path (output/<name>.tmp.png), which the engine opens with plain
os.Create— following any link left there and writing the render outside
the workspace. The tool then failed while reading the result back, so the
out-of-workspace write had already happened silently. That name is now
unlinked through the containment root before the path is handed out, so the
engine always creates the file fresh.
v0.26.4
Added
TestEveryRequiredNameIsDeclared— a schema that lists a name inrequired
without declaring it inpropertiesmakes a strict client refuse the whole
tool list (Vertex AI: "schema at top-level requires unspecified property").
data-toolbox-mcp shipped exactly that and broke a session outright; the
existing contract test checked declared ⇒ required only, so the fleet is
pinned in both directions now.
v0.26.3
Fixed
input_not_foundnamed nothing. "input %q is not in the workspace —
place it there first" does not say where the workspace is, and it reaches the
model on everyinit,mask,controlandupscaleinput. It now names the
absolute path it looked at. (Found on voice-scribe with a real agent, which
answered that sentence by inventing a directory and spent four rounds
recovering; these servers share the workspace code.)
v0.26.2
Fixed
- The initialize
instructionsfield never mentionedwork_dir. It is the
first thing the model reads about this server — before any tool list — and it
still described "a workspace directory you prepare" while every tool required
an argument it did not name. It now states the contract:work_diris the
absolute path of a directory you can read back, required, with no default.
Added
TestInstructionsNameTheWorkDirContract— the schema and description tests
walkedtools/list; nothing walked whatinitializereturns (ADR-0009).
v0.26.1
Fixed
- A stale comment still described
MCPConfigas falling back to a built-in
default workspace root; 0.26.0 removed both the key and the default. - Both READMEs still showed
image-forge mcp [--workspace-root <dir>]— a
flag 0.26.0 deleted — and the paragraph under it had been left half-rewritten
in either language.
Added
TestNoToolDescriptionNamesARetiredWorkDirName— the schema test pinned the
argument name, nothing pinned the sentences beside it.