Model or dataset
composio-community/secure-openclaw avatar
composio-community/secure-openclaw

Secure OpenClaw: a personal assistant on your messaging apps, with three dependencies pinned to the word latest

A personal 24x7 AI assistant like OpenClaw that runs on your messaging platforms. Send a message on WhatsApp, Telegram, Signal, or iMessage and get responses from Claude with full tool access, persistent memory, scheduled reminders, and integrations with 500+ apps.

1,189 stars169 forksJavaScriptMIT

At a glance

What is it?
This project puts a coding agent behind WhatsApp, Telegram, Signal and iMessage, with persistent memory and a few hundred app integrations. Its most useful lesson is a negative one: three of its eleven runtime dependencies are version-pinned to the literal string latest, and a project that executes an agent with tool access has no test suite at all.
Who is it for?
Secure OpenClaw is the right shape of project for somebody who wants a coding assistant on the phone they already carry, and it is a good demonstration of what an approval prompt in front of a tool router has to look like. It is a poor fit as a base to build on, because there is no test suite, no linter and three runtime dependencies versioned as latest, so a breaking change reaches you without a major version warning.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 68 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three dependencies pinned to the word latest

The manifest has eleven runtime dependencies, and the install is one command:

bash
git clone <repo-url> secure-openclaw
cd secure-openclaw
npm install

Eight of them have version ranges. Three of them are the literal string latest, and that is the most consequential line in the file.

Two of those three are the tool router client and the second provider's software development kit. The third is a library for one of the messaging platforms. The word latest in a manifest means that any resolution of the dependency tree, other than using a lockfile, will pick whatever the newest published version is. It is not a range and it is not a pin. It is an instruction to disregard semver entirely.

There is a lockfile in the repository, and that genuinely helps. If you install with a lockfile, you get the versions the author tested with, reproducibly. So the first install is fine and the second install six months later is not, because by then somebody has regenerated or discarded the lockfile, or run an update command, or built in an environment that resolves fresh. And when that happens, the failure mode is nasty: a library that chose to make a breaking change in a minor version will arrive without a major-version warning, because there is no range to violate.

The contrast inside the same file is what makes it interesting. The agent software development kit is a pre-1.0 release, and it is given a caret range, which for a zero major version permits only patch-level changes. That is a cautious pin written by somebody who understood the semantics. Two lines later, two dependencies are given the least cautious version specifier available. Both choices are defensible in isolation; the inconsistency suggests one was a considered decision and the others were convenience.

For a project where those libraries sit between you and five hundred application integrations, this matters more than it would in a smaller tool. The tool router is the thing that decides which of your accounts the assistant can reach, and a silently upgraded version of it is a silently upgraded authorisation path. Pinning it to an exact version and upgrading deliberately is a two-line change, and it is the difference between finding out about a change in a review and finding out about it in production.

The remaining line in the dependency list is unexplained, which is worth a mention because it is the kind of thing that makes a reader wonder whether the list was reviewed. A package whose name refers to a logo is a dependency of a gateway that runs an agent. It may be harmless. It is also the kind of entry you would expect to find explained in a comment.

There is no development dependency group, no test script, and no linter in the manifest. For a project of this shape that is a notable omission rather than a minor one, and the last section returns to it.

A project renamed twice, with every previous name kept in the topics

The topic list on this repository is a rename history.

There are ten topics, and they name the project three different ways. Two refer to a different name entirely. Two more refer to a third. And then there are the current name, with a plugin tag, a security tag, a skills tag, and a variant that looks like a daemon. None of the old names has been removed.

That is what happens to a project that has been renamed twice under time pressure, which is more common than the tidy repositories on your feed would suggest. The name changes because a name is taken, or because of a dispute, or because a package name was squatted. The repository is renamed. The readme is updated. And the topics, which are metadata nobody thinks about, keep the old names so that people searching for the thing they used to install still find it.

There is an argument for that. If a thousand people installed this under the first name, deleting the first-name topic means they cannot find the project any more. Keeping all three costs nothing and preserves a path back. So the mess is defensible, and it also means the topic list tells you nothing about what the project is called today, only about what it has been called.

The more substantive observation is what the name tells you about the project's position. This is a community project hosted under a company that also sells the tool router it depends on, and the readme's demo image links to that company's platform with campaign tracking parameters attached. The readme's own description and headings use the current name, and the badges credit the two toolchains the project actually runs on, which is accurate. But the sponsor and the supplier being the same organisation is a fact about the dependency graph rather than about the marketing, and a reader assessing whether five hundred integrations is a good idea should know that the answer comes from one vendor's catalogue.

None of this makes the project bad. It makes it worth reading the manifest before the readme, because the readme tells you what the project does and the manifest tells you what it depends on and who else is in the chain.

One security section, and a device pairing page with nothing in front of it

The project is named for security, it carries security tags, and its table of contents has no section called security. What it has instead is a section on tool approvals, and that section is the entire security model.

That is a defensible design rather than an omission. The central risk in a project like this is not that the assistant is malicious, it is that the assistant does something you did not want, through a tool, on your behalf. Approvals are the right control for that. The readme's feature list leads with full tool access, and the table of contents leads with tool approvals, and the pairing is deliberate: the capability is the point, and the control is what you do about it.

But two things are worth reading carefully. The first is what the approvals are actually gating. The integration layer reaches five hundred applications through a hosted service, so an approved tool call is a call into your Gmail, your issue tracker and your chat history, made by a router you do not control, authorised by a key that lives in a file on the machine. The approval prompt is therefore the last place where you can see what is about to happen, and it is the only place.

The second is the device pairing page. One of the supported messaging platforms is authenticated by scanning a QR code, and the readme tells you to open a URL on the server and scan the code with the app on your phone. That URL is a port on a machine you are about to expose to the internet, and the readme's own firewall instruction opens that port. There is nothing described between the port and the QR code: no token, no session, no mention of authentication on that page.

That is a real gap, and it is the kind that matters more than it looks. The code is generated by the server, so anybody who can reach the page is being offered the opportunity to scan it and link their own device to the account the server holds. For a personal assistant this may be an acceptable risk on a network only you can reach. On a box with a public address and an open port, it is the first thing to fix, and it is a small fix: put something in front of the page.

The third thing is quieter. The readme's feature list includes persistent memory, and the repository has a directory for sessions at the top level, outside any data directory. Wherever conversation transcripts land, they are the most sensitive thing this project holds, and the readme does not say where.

A six dollar host with no identity verification, and a build that needs more memory than it has

The remote deployment section is the most practically useful part of this readme, and also the part that should make you most uncomfortable. It is worth taking it in order.

It recommends a small single-server host at the lowest paid tier, and it says in one line why: no identity verification, just sign up and go. That is stated as a convenience, and it is a genuine convenience. It is also, for a box that will hold a model provider key, a key granting access to five hundred applications, and a paired messaging account, a choice with consequences. Identity verification at a host exists so that an account can be tied to a person. Declining it means the account cannot be tied to you if it is stolen, and the recovery path is a support conversation rather than a verification of identity.

The instructions then say to pick the cheapest plan, which is one gigabyte of memory, and set a root password. Root password rather than a key pair is the older and weaker option. Combined with a public address and an open port, the box is reachable by anyone who guesses the address and can then try passwords.

Then the honest part, and it is the reason the section is worth reading. The build needs more than one gigabyte of memory, so the instructions create a two gigabyte swap file, set its permissions, initialise it, enable it, and append it to the boot configuration so it survives a reboot. Then the troubleshooting section names the symptom: the build gets killed, exit code one hundred and thirty-seven, which is the kernel's out-of-memory signal. And the fix is the swap you already added.

So the project tells you to provision a machine too small for its own build, tells you how to work around it, and then tells you the exact exit code you will see when you did not. That is honest documentation. It is also an argument for a larger machine, and a sign that the one-gigabyte tier is the cheapest option rather than a tested one.

The firewall instruction is one line and it is necessary, because the application listens on a non-standard port that a default firewall will block. That is the normal case and the readme handles it. The container's service is named for the project's old name rather than its current one, which will not confuse anybody but will make you wonder briefly whether you are in the right directory.

The first command in the installation section is a placeholder

The installation section opens with a clone command, and the repository address in it is a placeholder. It is written as an angle-bracket token with the word repository in it, which is how a template marks a value the author intends to substitute and did not.

This is a trivial defect and I am describing it at length because of where it sits. It is step one of the installation. A reader who copies it gets a command that either fails immediately or, worse, is edited into something that clones the wrong thing. Everything after it, including several pages of genuinely careful instructions, is behind a command that does not work as printed.

The same pattern appears again in the remote deployment section, where the clone command is for a repository address with a username token in it, described as being for the case where the project is private and a personal access token is needed. That one is a template too, and the troubleshooting section has an entry for private clones failing, with the correct answer: the forge does not support password authentication for clones, so a token is required. So the readme explains a failure caused by the very thing its placeholder command invites.

Both instances point at the same cause. The instructions are written to be copied into a repository under somebody else's account, which means they cannot contain a real address. That is a reasonable constraint for a project meant to be forked, and a reasonable way to ship instructions, and it is a bad way to ship step one.

The fix is a single line pointing at the canonical address, which the readme does elsewhere, in the description and in a repository link. The information was there. It just was not in the place somebody would look first.

It is worth contrasting this with the rest of the deployment section, which is detailed to an unusual standard. The firewall command is given. The health check URL is given. The update command is given as a single line combining a pull and a rebuild. The shell-into-the-container command is given. The log commands are given. Every one of those was clearly written by somebody who had done it, and the clone command was not.

Two authentication models for the same assistant, chosen by deployment

The same assistant has two completely different authentication stories, and the readme explains the switch in a single sentence that is easy to skim.

Run it on your machine and you authenticate the provider by running its command and following an interactive login flow, which uses an OAuth exchange against your provider account. No key in a file, no key in a shell profile, and the credential is held by the tool rather than by you.

Run it on a remote machine or in a container and there is no interactive login available, so authentication becomes an environment variable holding a long-lived key, exported in your shell profile on one machine or written into a configuration file on the other.

That is the right answer for the two situations. A developer at a terminal can do an OAuth flow, and a container cannot. The consequence, which the readme does not spell out, is that the two deployments have different security properties. The local one has a credential held by a tool that can refresh it. The remote one has a credential in a file, on a box you reach over a connection you configured, running as a user whose password you set by hand in the instructions.

The provider situation is the same shape. There are two supported providers, each installed by a different mechanism, one through the package manager and one through a script fetched over the network and piped to a shell. The readme says you can install both and switch between them, which is a good design for comparing two assistants on the same tasks.

But switching providers changes more than which model answers. Each provider is a separate tool with its own configuration, its own authentication and its own tool set, and the agent layer above them is a wrapper around whichever one is selected. That means the effective capability of this assistant is a function of the provider you chose and the tools that provider exposes, not of this project alone. Worth knowing before you compare it to something that has a fixed tool surface.

The application integration layer has the same property once more. It is a hosted service with its own login, its own key and its own catalogue, and the readme obtains the key by running a whoami command after logging in. So there are three separate credentials in the setup, from three separate organisations, and any assessment of the security properties has to account for all three.

Troubleshooting that names exit codes, log lines and a private address range

The troubleshooting section is the best-written documentation in this repository, and it is worth reading as a genre rather than as a list.

Five entries, and every one is a specific failure with a specific cause. A build that is killed, with the exit code given, caused by memory. A page that will not load, with two possible causes: the firewall rule is missing, or you are using the wrong address. The second of those is the one people actually hit, and the readme identifies it by saying the wrong one starts with a particular digit. That is an extraordinary level of specificity for a documentation entry, and it is exactly the kind of thing that only gets written by somebody who watched three people make the same mistake.

The pairing page that appears to be stuck is handled the same way. The readme tells you the page saying it is waiting means the service has not finished starting, tells you the exact log line to wait for, and tells you the command to get the logs. A status message that looks like a hang is therefore diagnosable in one step, which is the whole purpose of a status message.

Then the two entries that are pure operational knowledge. A provider process exiting with a failure code means the key is missing or wrong, and the readme gives you the command to check the variable inside the running container rather than in your local shell, which is the right place to look and the place people do not look. A private clone failing means the forge does not accept a password, and the fix is a token.

This is documentation as institutional memory. Every entry is a question somebody asked, and the answer includes the diagnostic command as well as the fix, which means the reader can confirm rather than trust.

Which makes the absence elsewhere more noticeable. There is no test suite in the manifest, no linter, and no development dependencies at all, in a project that runs an agent with access to five hundred applications. The troubleshooting section is what happens when you have users and no tests, and it is good, and it is a substitute rather than a solution. The things a test suite would catch here are the wrong kind of problem: a changed configuration key, a renamed function, an integration whose response shape moved. Those are the failures that produce a broken assistant rather than a failed build, and they are exactly the ones a deployed system discovers for you, in front of a user, at three in the morning.

Editorial conclusion

Secure OpenClaw is the right shape of project for somebody who wants a coding assistant on the phone they already carry, and it is a good demonstration of what an approval prompt in front of a tool router has to look like. It is a poor fit as a base to build on, because there is no test suite, no linter and three runtime dependencies versioned as latest, so a breaking change reaches you without a major version warning. Before running it on a machine with a public address, put something in front of the device pairing page, because the readme tells you to open that port and describes no authentication on it, and pin the tool router to an exact version so an upgrade to its authorisation path is a decision you make rather than one that happens.

Frequently asked questions

What does secure-openclaw do?

It runs a coding agent behind four messaging platforms, so you can send a message from WhatsApp, Telegram, Signal or iMessage and get a reply with tool access, persistent memory, scheduled reminders, and integrations with several hundred applications through a hosted tool router service.

Why are some of the secure-openclaw dependencies versioned as latest?

Three of the eleven runtime dependencies use the literal string latest as their version specifier, which means any fresh resolution picks whatever is newest with no semver constraint. A lockfile protects a given install, but not the next one, and for a library that mediates access to several hundred applications a silently upgraded version is an upgraded authorisation path.

How does secure-openclaw authenticate its model provider?

Two different models depending on deployment. Locally you run the provider's command and complete an interactive login flow. On a remote machine or in a container, where no interactive login is possible, authentication becomes a long-lived API key held in an environment variable or a configuration file.

What security controls does secure-openclaw actually have?

The repository is named for security and the readme's contents has no security section; what it has is a tool approvals section, which is the control on the central risk, which is the assistant doing something unintended through a tool. The device pairing page for one messaging platform is described with no authentication in front of it, and the readme instructs you to open that page's port on a public host.

What hardware does the remote deployment need?

The readme recommends the cheapest single-server plan, which has one gigabyte of memory, and then states that the build needs more than that, with instructions for adding a two gigabyte swap file and a troubleshooting entry for the build being killed with the kernel's out-of-memory exit code. The cheapest tier is a starting point rather than a tested configuration.

Official sources

  1. composio-community/secure-openclaw on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/composio-community-secure-openclaw.svg)](https://hysenlabs.com/projects/composio-community-secure-openclaw)