diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 84071d042c85643dfc181549f038e46c9c4b354a..f2398732994160a13b949f79825060221d53587f 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -145,6 +145,7 @@ typedef _Bool bool;
 #define API_CONFIG_GET_STRING      0x130
 #define API_CONFIG_GET_INTEGER     0x131
 #define API_CONFIG_GET_BOOLEAN     0x132
+#define API_CONFIG_SET_STRING      0x133
 /* clang-format on */
 
 typedef uint32_t api_int_id_t;
@@ -2060,5 +2061,21 @@ API(API_CONFIG_GET_BOOLEAN, int epic_config_get_boolean(const char *key, bool *v
 API(API_CONFIG_GET_STRING, int epic_config_get_string(const char *key, char *buf, size_t buf_len));
 
 
+/**
+ * Write a string to the configuration file.
+ *
+ * :param char* key: Name of the option to write
+ * :param char* value: The value to write
+ * :return: `0` on success or a negative value if an error occured. Possivle
+ *    errors:
+ *
+ *    - ``-EINVAL``: Parameters out of range
+ *    - ``-ENOENT``: Key already exists but can not be read
+ *    - ``-EIO``   : Unspecified I/O error
+ *    - Any fopen/fread/fwrite/fclose related error code
+ *
+ * .. versionadded:: 1.16
+ */
+API(API_CONFIG_SET_STRING, int epic_config_set_string(const char *key, const char *value));
 #endif /* _EPICARDIUM_H */
 
diff --git a/epicardium/modules/config.c b/epicardium/modules/config.c
index 922dae657fe78be03280d5145bba651c0b6cbfd6..6874318a1e3f0bdfa58cd61dd4f81b584eaa26ff 100644
--- a/epicardium/modules/config.c
+++ b/epicardium/modules/config.c
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <stddef.h>
+#include <stdio.h>
 
 #define MAX_LINE_LENGTH 80
 #define KEYS_PER_BLOCK 16
@@ -381,3 +382,222 @@ bool config_get_boolean_with_default(const char *key, bool default_value)
 		return value;
 	}
 }
+
+// TODO: don't allow things like "execute_elf" to be set
+int epic_config_set_string(const char *key, const char *value)
+{
+	config_slot *slot = find_config_slot(key);
+	bool present      = slot && slot->value_offset;
+	int ret           = 0;
+
+	if (snprintf(NULL, 0, "\n%s = %s\n", key, value) > MAX_LINE_LENGTH) {
+		return -EINVAL;
+	}
+
+	if (!present) {
+		/* Easy case: We simply add the new option at the
+		 * end of the file. */
+
+		char buf[MAX_LINE_LENGTH];
+		/* Leading new line because I'm lazy */
+		ret = snprintf(buf, sizeof(buf), "\n%s = %s\n", key, value);
+
+		if (ret < 0 || ret >= (int)sizeof(buf)) {
+			return -EINVAL;
+		}
+
+		int fd = epic_file_open("card10.cfg", "a");
+		if (fd < 0) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"open for appending failed: %s (%d)",
+				strerror(-fd),
+				fd
+			);
+			return fd;
+		}
+
+		int write_ret = epic_file_write(fd, buf, strlen(buf));
+		if (write_ret < 0) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"writing failed: %s (%d)",
+				strerror(-write_ret),
+				write_ret
+			);
+		}
+
+		if (write_ret < (int)strlen(buf)) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"writing failed to write all bytes (%d of %d)",
+				write_ret,
+				strlen(buf)
+			);
+		}
+
+		ret = epic_file_close(fd);
+
+		if (ret < 0) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"close failed: %s (%d)",
+				strerror(-ret),
+				ret
+			);
+		}
+		if (write_ret < 0) {
+			return write_ret;
+		}
+		if (ret < 0) {
+			return ret;
+		}
+		if (write_ret < (int)strlen(buf)) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"writing failed to write all bytes (%d of %d)",
+				write_ret,
+				strlen(buf)
+			);
+			return -EIO;
+		}
+	} else {
+		/* Complex case: The value is already somewhere in the file.
+		 * We do not want to lose existing formatting or comments.
+		 * Solution: Copy parts of the file, insert new value, copy
+		 * rest, rename.
+		 */
+		char buf[128];
+		int fd1 = -1;
+		int fd2 = -1;
+		ret     = epic_config_get_string(key, buf, sizeof(buf));
+
+		if (ret < 0) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"could not read old value (%d)",
+				ret
+			);
+			goto out;
+		}
+
+		int old_len = strlen(buf);
+
+		fd1 = epic_file_open("card10.cfg", "r");
+		if (fd1 < 0) {
+			LOG_DEBUG(
+				"card10.cfg",
+				"open for read failed: %s (%d)",
+				strerror(-fd1),
+				fd1
+			);
+			ret = fd1;
+			goto out;
+		}
+
+		fd2 = epic_file_open("card10.nfg", "w");
+		if (fd2 < 0) {
+			LOG_DEBUG(
+				"card10.nfg",
+				"open for writing failed: %s (%d)",
+				strerror(-fd2),
+				fd2
+			);
+			ret = fd2;
+			goto out;
+		}
+
+		/* Copy over slot->value_offset bytes */
+		int i = slot->value_offset;
+		while (i > 0) {
+			int n = i > (int)sizeof(buf) ? (int)sizeof(buf) : i;
+			ret   = epic_file_read(fd1, buf, n);
+			if (ret < 0) {
+				LOG_DEBUG(
+					"card10.cfg",
+					"read failed: rc: %d",
+					ret
+				);
+				goto out;
+			}
+
+			int ret2 = epic_file_write(fd2, buf, ret);
+
+			if (ret2 < 0) {
+				ret = ret2;
+				LOG_DEBUG(
+					"card10.nfg",
+					"write failed: rc: %d",
+					ret
+				);
+				goto out;
+			}
+			i -= ret;
+		}
+
+		/* Insert new value into the new file */
+		ret = epic_file_write(fd2, value, strlen(value));
+		if (ret < 0) {
+			LOG_DEBUG("card10.nfg", "write failed: rc: %d", ret);
+			goto out;
+		}
+
+		/* Skip the old value inside the old file */
+		epic_file_seek(fd1, old_len, SEEK_CUR);
+
+		/* Copy the rest of the old file to the new file */
+		while (true) {
+			int ret = epic_file_read(fd1, buf, sizeof(buf));
+
+			if (ret == 0) {
+				break;
+			}
+
+			if (ret < 0) {
+				LOG_DEBUG(
+					"card10.cfg",
+					"read failed: rc: %d",
+					ret
+				);
+				goto out;
+			}
+
+			int ret2 = epic_file_write(fd2, buf, ret);
+
+			if (ret2 < 0) {
+				ret = ret2;
+				LOG_DEBUG(
+					"card10.nfg",
+					"write failed: rc: %d",
+					ret
+				);
+				goto out;
+			}
+
+			if (ret < (int)sizeof(buf)) {
+				break;
+			}
+		}
+
+	out:
+		if (fd1 >= 0) {
+			epic_file_close(fd1);
+		}
+		if (fd2 >= 0) {
+			int ret2 = epic_file_close(fd2);
+			if (ret >= 0) {
+				ret = ret2;
+			}
+		}
+
+		if (ret >= 0) {
+			epic_file_unlink("card10.cfg");
+			epic_file_rename("card10.nfg", "card10.cfg");
+		}
+	}
+
+	/* Reload config so the new key or the changed value is available */
+	load_config();
+
+	return ret < 0 ? ret : 0;
+}