diff --git a/commonmark/src/main/java/org/commonmark/internal/util/AsciiMatcher.java b/commonmark/src/main/java/org/commonmark/internal/util/AsciiMatcher.java
index 82d83ca46f38341e817efd4dcc6f02d726cffa68..35769f82ddd47280816a95e33f5aea45274fb562 100644
--- a/commonmark/src/main/java/org/commonmark/internal/util/AsciiMatcher.java
+++ b/commonmark/src/main/java/org/commonmark/internal/util/AsciiMatcher.java
@@ -29,6 +29,13 @@ public class AsciiMatcher implements CharMatcher {
             this.set = set;
         }
 
+        public Builder anyOf(String s) {
+            for (int i = 0; i < s.length(); i++) {
+                c(s.charAt(i));
+            }
+            return this;
+        }
+
         public Builder c(char c) {
             if (c > 127) {
                 throw new IllegalArgumentException("Can only match ASCII characters");
diff --git a/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java b/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
index 813efb1649acfe63c37fbd5abdf278f657b152ad..fe5725aee3c958b5e246ddcc7f408a0777f7f8cc 100644
--- a/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
+++ b/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
@@ -10,6 +10,8 @@ import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * The node renderer that renders all the core nodes (comes last in the order of node renderers).
@@ -20,8 +22,8 @@ import java.util.Set;
  */
 public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRenderer {
 
-    private final CharMatcher textEscape =
-            AsciiMatcher.builder().c('[').c(']').c('<').c('>').c('`').build();
+    private final AsciiMatcher textEscape =
+            AsciiMatcher.builder().anyOf("[]<>`*&").build();
     private final CharMatcher linkDestinationNeedsAngleBrackets =
             AsciiMatcher.builder().c(' ').c('(').c(')').c('<').c('>').c('\\').build();
     private final CharMatcher linkDestinationEscapeInAngleBrackets =
@@ -29,6 +31,8 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
     private final CharMatcher linkTitleEscapeInQuotes =
             AsciiMatcher.builder().c('"').build();
 
+    private final Pattern orderedListMarkerPattern = Pattern.compile("^([0-9]{1,9})([.)])");
+
     protected final MarkdownNodeRendererContext context;
     private final MarkdownWriter writer;
     /**
@@ -319,7 +323,55 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
 
     @Override
     public void visit(Text text) {
-        writer.writeEscaped(text.getLiteral(), textEscape);
+        String literal = text.getLiteral();
+        if (writer.isAtLineStart() && !literal.isEmpty()) {
+            char c = literal.charAt(0);
+            switch (c) {
+                case '-': {
+                    // Would be ambiguous with a bullet list marker, escape
+                    writer.write("\\-");
+                    literal = literal.substring(1);
+                    break;
+                }
+                case '#': {
+                    // Would be ambiguous with an ATX heading, escape
+                    writer.write("\\#");
+                    literal = literal.substring(1);
+                    break;
+                }
+                case '=': {
+                    // Would be ambiguous with a Setext heading, escape
+                    writer.write("\\=");
+                    literal = literal.substring(1);
+                    break;
+                }
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9': {
+                    // Check for ordered list marker
+                    Matcher m = orderedListMarkerPattern.matcher(literal);
+                    if (m.find()) {
+                        writer.write(m.group(1));
+                        writer.write("\\" + m.group(2));
+                        literal = literal.substring(m.end());
+                    }
+                }
+            }
+        }
+
+        if (literal.endsWith("!") && text.getNext() instanceof Link) {
+            writer.writeEscaped(literal.substring(0, literal.length() - 1), textEscape);
+            writer.write("\\!");
+        } else {
+            writer.writeEscaped(literal, textEscape);
+        }
     }
 
     @Override
diff --git a/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java b/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java
index ba682d465cbd14ce97fb4c46c38cc737faa8f9b1..bc10f020e3057c071cdcee178080996b508363ab 100644
--- a/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java
+++ b/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java
@@ -11,7 +11,7 @@ public class MarkdownWriter {
 
     private int blockSeparator = 0;
     private boolean tight;
-    private char lastChar;
+    private char lastChar = '\n';
     private final LinkedList<String> prefixes = new LinkedList<>();
 
     public MarkdownWriter(Appendable out) {
@@ -22,6 +22,10 @@ public class MarkdownWriter {
         return lastChar;
     }
 
+    public boolean isAtLineStart() {
+        return lastChar == '\n' || blockSeparator > 0;
+    }
+
     public void write(String s) {
         flushBlockSeparator();
         append(s);
diff --git a/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java b/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
index 76a77dbb5900227ef52665826002b24178e63141..59039799aca62fcac5bfac3e4d44ee5720a6a432 100644
--- a/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
+++ b/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
@@ -127,6 +127,22 @@ public class MarkdownRendererTest {
         // otherwise result in a different parse result (e.g. a link):
         assertRoundTrip("\\[a\\](/uri)\n");
         assertRoundTrip("\\`abc\\`\n");
+
+        // Some characters only need to be escaped at the beginning of the line
+        assertRoundTrip("\\- Test\n");
+        assertRoundTrip("\\-\n");
+        assertRoundTrip("Test -\n");
+        assertRoundTrip("Abc\n\n\\- Test\n");
+        assertRoundTrip("\\# Test\n");
+        assertRoundTrip("\\## Test\n");
+        assertRoundTrip("\\#\n");
+        assertRoundTrip("Foo\n\\===\n");
+
+        // This is a bit more tricky as we need to check for a list start
+        assertRoundTrip("1\\. Foo\n");
+        assertRoundTrip("999\\. Foo\n");
+        assertRoundTrip("1\\.\n");
+        assertRoundTrip("1\\) Foo\n");
     }
 
     @Test
diff --git a/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java b/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java
index 2a0c46c00a0c573a7a30b482d13799251643adfe..632f4acfc786474c0933b79078ec4214f8dd3516 100644
--- a/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java
+++ b/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java
@@ -62,7 +62,7 @@ public class SpecMarkdownRendererTest {
             System.out.println();
         }
 
-        int expectedPassed = 630;
+        int expectedPassed = 646;
         assertTrue("Expected at least " + expectedPassed + " examples to pass but was " + passes.size(), passes.size() >= expectedPassed);
     }