Hugging Face publishes smolagents. Tool.from_langchain
wraps a LangChain tool. Each positional
forward value was written onto the first input
key. A two-arg call collapses to one field. The patch is in
PR 2763.
| Document | HB-AR-2026.7 / public source review, LangChain tool wrapper |
|---|---|
| What this is | A research note and an opinion. Hugging Face did not hire Hackerbane for this. |
| System | huggingface/smolagents, Tool.from_langchain |
| Scope |
LangChainToolWrapper.forward in
src/smolagents/tools.py
|
| Review commit | main @ 30bb116 |
| Upstream | PR 2763 (open) · #2762 |
| Date | 7 September 2026 |
| Author | Barney Chambers, Hackerbane |
If you have not used smolagents: it is Hugging Face's small agent library. One helper wraps a LangChain tool so an agent can call it. Keyword arguments already land on the right keys. Positional arguments did not.
On main at commit 30bb116:
for index, argument in enumerate(args):
if index < len(self.inputs):
input_key = next(iter(self.inputs))
tool_input[input_key] = argument
# forward(3, 7) -> {"first": 7}
I opened a patch that indexes the keys in declaration order. It is PR 2763, against #2762. Hugging Face did not hire this review. The name on the cover names the project I read.
Their CONTRIBUTING asks for an accepted issue before a
patch. I filed the issue and the PR together. Their bot
may tag the PR needs-issue until a
maintainer accepts #2762. That is their process, not a
merge.
| # | ID | Action | Status on 7 Sep 2026 |
|---|---|---|---|
| 1 | MED-01 | Bind positional LangChain args by key index, not by repeating the first key. | Patch open. PR 2763. Issue #2762. |
This is not a full audit of smolagents. I split the tree
and read the local executor, remote executors, default
tools, serialization, and the LangChain wrapper. Hugging
Face's SECURITY.md says the local executor is not a
security boundary, and it asks that suspected
vulnerabilities go through private reporting. I did not
open a public security PR for executor bypasses. The
finding I can prove with a unit test on current
main, and that was not already in an open
PR, is the LangChain positional map.
| In scope |
src/smolagents/tools.py
Tool.from_langchain /
LangChainToolWrapper.forward.
Tests in tests/test_tools.py.
|
|---|---|
| Out of scope |
Local executor dunder bypasses (they already have
public security work on that surface). Agent
save/from_dict field loss
that already has open PRs. Sandboxed remote
backends. Prompt injection into
VisitWebpageTool.
|
| Method |
Read forward. Compare keyword mapping
with positional mapping. Add pytest cases that fail
on 30bb116 and pass with the patch.
|
| Retest |
PYTHONPATH=src python3 -m pytest tests/test_tools.py::test_from_langchain_maps_positional_args_in_declaration_order tests/test_tools.py::test_from_langchain_accepts_keyword_and_mixed_args -q
|
| ID | Severity | Title | Status |
|---|---|---|---|
| MED-01 | Medium | from_langchain writes every positional arg onto the first key | Patch open (PR 2763) |
I called this Medium, not High, because keyword and tool-calling JSON paths already work. The miss is the positional path on a wrapper, not the default built-in tools.
src/smolagents/tools.py · Tool.from_langchain · LangChainToolWrapper.forward
The loop already has an index. It never uses it for
the key. next(iter(self.inputs)) is the
first name every time. On
30bb116,
forward(3, 7) returns
{"first": 7}. After the patch it returns
{"first": 3, "second": 7}.
Keyword-only and mixed
forward(3, second=7) already worked.
The new tests keep those paths.
| When | What |
|---|---|
| 7 Sep 2026 |
Review commit 30bb116. MED-01 confirmed.
The positional test fails on that commit and passes
with the patch. 2 passed with the patch.
|
| 7 Sep 2026 | Opened #2762 and PR 2763. Still open when this note was written. Their CONTRIBUTING may close an unaccepted PR after 14 days. |
To retest MED-01, run the command in section 2.
Read this before you treat anything above as advice.
This file is a public research note. Hugging Face did not hire Hackerbane. There is no services agreement, statement of work, or client relationship behind it. The Hugging Face name on the cover names the project I read. It is not a partnership badge.
What you have is an opinion about the files and commits named in section 2. It is not a certificate. It is not an endorsement of Hugging Face, of smolagents, or of the patch. It is not a claim that the rest of smolagents is safe, or that it is broken.
I am not telling you to merge, deploy, buy, or sell anything. This is not investment advice, legal advice, or a security guarantee. If you ship software, you own that risk. If you wrap LangChain tools, you own that risk.
Hackerbane and I accept no liability for how anyone uses this note, for bugs it does not name, or for loss that follows from relying on it. Findings can be wrong, incomplete, or already stale the day after the review commit. Code added after that commit was not reviewed. A retest covers only the checks it names.
You may share this file. Sharing it does not create a contract and does not make the reader a client.
This note is provided as-is, as available, with all faults. To the maximum extent the law allows, Hackerbane disclaims every warranty, express or implied, including merchantability, fitness for a particular purpose, title, and non-infringement. No promise that this text is accurate, complete, or free of error, or that any error will be fixed.
Nobody may rely on this note as a professional engagement. It is not financial, tax, legal, or regulatory advice. No third party is a beneficiary of it.
| Critical | Someone could steal funds or hurt people with what I looked at. |
|---|---|
| High | The check you think you have does not work in the common case. |
| Medium | A real miss, less common in the output I care about here. |
| Low | Real, but limited, or it needs an unlikely setup. |
| Informational | On the record. Not scored as a bug. |
The coloured bars are labels. The word High or Medium is what counts.